| import java.applet.*; import java.awt.*; import java.math.*; import java.net.URL; public class BigCalculator extends Applet implements Runnable { public static final BigInteger UNITY = new BigInteger("1"); public static final BigDecimal ZERO = new BigDecimal(0.0d); public static final BigDecimal QUARTER = new BigDecimal(0.25d); public static final BigDecimal HALF = new BigDecimal(0.5d); public static final BigDecimal ONE = new BigDecimal(1.0d); public static final BigDecimal TWO = new BigDecimal(2.0d); public static final BigDecimal TEN = new BigDecimal(10.0d); public static final BigDecimal ONE_EIGHTY = new BigDecimal(180.0d); public static final BigDecimal PI = set_PI(); public static final BigDecimal LN10 = set_LN10(); public static final int RHU = BigDecimal.ROUND_HALF_UP; Thread crunch = new Thread(this); boolean breakSignal = false; String commandString = "none" ; // serves as the "parameter" for run(). TextField display,digits_field,DRG_field; boolean firstDigit = true; BigDecimal operand1 = ZERO; String operator = "="; //Initial operator BigDecimal memory[]; Canvas busy; int digits; int default_digits = 80; boolean degrees = false; boolean inDigitsField = false; boolean clearButtonFlag = false; Button feedback_button; URL feedback_URL; //-------------------------------------------------------------------- public void init() { /* Initialize everybody */ digits = default_digits; memory = new BigDecimal[3]; memory[0] = ZERO; memory[1] = ZERO; memory[2] = ZERO; display = new TextField("0"); display.setEditable(false); display.setBackground(Color.black); display.setForeground(Color.green); digits_field = new TextField(Integer.toString(digits)); digits_field.setBackground(Color.gray); digits_field.setFont(new Font("Helvetica", Font.BOLD, 12)); DRG_field = new TextField("RAD"); DRG_field.setEditable(false); DRG_field.setBackground(Color.black); DRG_field.setForeground(Color.yellow); DRG_field.setFont(new Font("Helvetica", Font.PLAIN, 12)); busy = new Canvas(); GridBagLayout gb = new GridBagLayout(); this.setLayout(gb); this.setFont(new Font("Helvetica", Font.BOLD, 16)); this.setBackground(Color.darkGray); Label title_label = new Label("BIG CALCULATOR",Label.CENTER); title_label.setFont(new Font("Helvetica", Font.BOLD, 16)); title_label.setForeground(Color.white); Label subt_label = new Label("An arbitrary precision calculator", Label.CENTER); subt_label.setForeground(Color.white); Label digits_label = new Label("digits:",Label.RIGHT); digits_label.setForeground(Color.white); feedback_button = new Button("by Jason Tiscione"); feedback_button.setForeground(Color.white); feedback_button.setBackground(Color.darkGray); feedback_button.setFont(new Font("Helvetica", Font.ITALIC, 12)); try { feedback_URL = new URL("mailto:[email protected]"); } catch (java.net.MalformedURLException exc) {} /* Lay everything out */ int NONE=GridBagConstraints.NONE; int BOTH=GridBagConstraints.BOTH; int CENTER=GridBagConstraints.CENTER; int HORIZONTAL=GridBagConstraints.HORIZONTAL; Color syscol = Color.lightGray; Color stdcalc = Color.gray; Color breakcol = Color.getHSBColor(0.01f,0.5f,0.6f); Color scicalc = Color.getHSBColor(0.9f,0.2f,0.5f); Color memcol = Color.getHSBColor(0.6f,0.2f,0.5f); Color trigcol = Color.getHSBColor(0.1f,0.2f,0.5f); try { addComponent(this,title_label,0,0,10,1,HORIZONTAL,CENTER,0,0,0); addComponent(this,subt_label,3,1,4,1,HORIZONTAL,CENTER,0,0,0); addComponent(this,display,0,2,10,1,HORIZONTAL,CENTER,0,0,0); addComponent(this,feedback_button,8,1,2,1,HORIZONTAL,CENTER,0,0,5); addComponent(this,digits_label,0,3,1,1,HORIZONTAL,CENTER,0,0,0); addComponent(this,digits_field,1,3,1,1,HORIZONTAL,CENTER,0,0,0); addButton(new Button ("roundoff"),2,3,2,1,syscol); addButton(new Button ("backspace"),4,3,2,1,syscol); addComponent(this,DRG_field,6,3,1,1,HORIZONTAL,CENTER,0,0,8); addButton(new Button ("break"),7,3,2,1,breakcol); addComponent(this,busy,9,3,1,1,HORIZONTAL,CENTER,15,15,0); addButton(new Button ("CE/C"),0,4,1,1,syscol); addButton(new Button ("\u00f7"),1,4,1,1,stdcalc); //division symbol addButton(new Button ("\u00d7"),2,4,1,1,stdcalc); //mult. symbol addButton(new Button ("-"),3,4,1,1,stdcalc); addButton(new Button ("e^x"),4,4,1,1,scicalc); addButton(new Button ("10^x"),5,4,1,1,scicalc); addButton(new Button ("M3+"),6,4,1,1,memcol); addButton(new Button ("M3-"),7,4,1,1,memcol); addButton(new Button ("M3R"),8,4,1,1,memcol); addButton(new Button ("M3C"),9,4,1,1,memcol); addButton(new Button ("7"),0,5,1,1,stdcalc); addButton(new Button ("8"),1,5,1,1,stdcalc); addButton(new Button ("9"),2,5,1,1,stdcalc); addButton(new Button ("+"),3,5,1,2,stdcalc); addButton(new Button ("ln"),4,5,1,1,scicalc); addButton(new Button ("log"),5,5,1,1,scicalc); addButton(new Button ("M2+"),6,5,1,1,memcol); addButton(new Button ("M2-"),7,5,1,1,memcol); addButton(new Button ("M2R"),8,5,1,1,memcol); addButton(new Button ("M2C"),9,5,1,1,memcol); addButton(new Button ("4"),0,6,1,1,stdcalc); addButton(new Button ("5"),1,6,1,1,stdcalc); addButton(new Button ("6"),2,6,1,1,stdcalc); addButton(new Button ("sqrt"),4,6,1,1,scicalc); addButton(new Button ("rootn"),5,6,1,1,scicalc); addButton(new Button ("M1+"),6,6,1,1,memcol); addButton(new Button ("M1-"),7,6,1,1,memcol); addButton(new Button ("M1R"),8,6,1,1,memcol); addButton(new Button ("M1C"),9,6,1,1,memcol); addButton(new Button ("1"),0,7,1,1,stdcalc); addButton(new Button ("2"),1,7,1,1,stdcalc); addButton(new Button ("3"),2,7,1,1,stdcalc); addButton(new Button ("="),3,7,1,2,stdcalc); addButton(new Button ("1/x"),4,7,1,1,scicalc); addButton(new Button ("x^y"),5,7,1,1,scicalc); addButton(new Button ("pi"),6,7,1,1,trigcol); addButton(new Button ("arcsin"),7,7,1,1,trigcol); addButton(new Button ("arccos"),8,7,1,1,trigcol); addButton(new Button ("arctan"),9,7,1,1,trigcol); addButton(new Button ("0"),0,8,2,1,stdcalc); addButton(new Button ("."),2,8,1,1,stdcalc); addButton(new Button ("+/-"),4,8,1,1,scicalc); addButton(new Button ("x!"),5,8,1,1,scicalc); addButton(new Button ("R-D"),6,8,1,1,trigcol); addButton(new Button ("sin"),7,8,1,1,trigcol); addButton(new Button ("cos"),8,8,1,1,trigcol); addButton(new Button ("tan"),9,8,1,1,trigcol); } catch (AWTException e) { System.out.println("AWTException"); e.printStackTrace(); } crunch.start(); } //-------------------------------------------------------------------- public void destroy() { crunch.stop(); } //-------------------------------------------------------------------- public void start() { crunch.resume(); } //-------------------------------------------------------------------- public void stop() { crunch.suspend(); } //-------------------------------------------------------------------- public boolean mouseMove(Event e, int x, int y) { if (feedback_button.bounds().inside(x,y)) { this.showStatus("Email me questions, comments, bug reports, job offers..."); return true; } return false; } //-------------------------------------------------------------------- public boolean gotFocus(Event e, Object arg) { if (e.target == digits_field) { inDigitsField=true; } else { inDigitsField=false; return false; } return true; } //-------------------------------------------------------------------- public boolean lostFocus(Event e, Object arg) { if (e.target == digits_field) { int numberEntered; try { numberEntered = Integer.parseInt(digits_field.getText()); } catch (NumberFormatException exc) { // invalid entry numberEntered=default_digits; digits_field.setText(Integer.toString(numberEntered)); } if (numberEntered < 1) { // also an invalid entry numberEntered=default_digits; digits_field.setText(Integer.toString(numberEntered)); } digits = numberEntered; inDigitsField=false; } else { inDigitsField=true; return false; } return true; } //-------------------------------------------------------------------- public boolean action (Event e, Object arg) { if (e.target instanceof Button) { if (e.target==feedback_button) { try { this.getAppletContext().showDocument (feedback_URL, "_blank"); return true; } catch (Exception exc) { return true; } } String argstr = (String)arg; if (argstr.equalsIgnoreCase("break")) { breakSignal = true; } else { synchronized (commandString) { commandString = argstr; } } return true; } return false; // only if event was not a button press } //-------------------------------------------------------------------- public boolean keyDown(Event e, int key) { if((e.id==Event.KEY_PRESS) && (inDigitsField != true)) { synchronized (commandString) { switch (key) { case 10: // User pressed ENTER commandString = "="; break; case 8: // User pressed backspace key commandString = "backspace"; break; case 127: // User pressed delete key commandString = "backspace"; break; case 27: // User pressed escape key breakSignal = true; break; default: char dummyarg[] = { (char)key }; commandString = new String(dummyarg); } } return true; } return false; // only if event was not a keypress } //-------------------------------------------------------------------- public void run() { // crunch thread runs in an endless loop. If commandString is // set to a value by the main thread, crunch will grab it. // Therefore a synchronization lock is placed on all code in this // applet that reads or sets commandString. String s; while (true) { synchronized (commandString) { s=commandString; commandString = "none"; } if (!(s.equalsIgnoreCase("none"))) { light(true); discriminate(s); light(false); if (breakSignal) { // break key was hit- so do cleanup display.setText("0"); operator = "="; operand1 = ZERO; clearButtonFlag = false; firstDigit = true; breakSignal = false; } } } } //-------------------------------------------------------------------- private void discriminate(String s) { // if any key other than CE/C is pressed, clear clearButtonFlag if (!(s.equalsIgnoreCase("CE/C") ||s.equalsIgnoreCase("c"))) { clearButtonFlag = false; } if (s.equalsIgnoreCase("backspace")&&!firstDigit){ String disp = display.getText(); disp = disp.substring(0,disp.length()-1); if (disp.length()==0) { disp="0"; firstDigit=true; } display.setText(disp); } if ("0123456789.".indexOf(s) != -1) { // s contains either a digit or a decimal point if (firstDigit) { firstDigit=false; display.setText(s); } else { display.setText(display.getText() + s); } } else { String coplist = "= + - x * / \u00d7 \u00f7 x^y rootn"; if (coplist.indexOf(s) != -1) { //a conjunctive operator conjunctive (display.getText()); firstDigit = true; operator = s; } else { String uoplist = "C CE/C c M1+ M1- M1R M1C M2+ M2- M2R M2C" + " M3+ M3- M3R M3C +/- 1/x sqrt ln e^x log 10^x pi x!" + " sin cos tan arcsin arccos arctan R-D roundoff "; if (uoplist.indexOf(s) != -1) { //s is a unary operator unary (display.getText(),s); firstDigit = true; } } } } //-------------------------------------------------------------------- private void conjunctive (String disp) { BigDecimal operand2; try { operand2 = new BigDecimal(disp); } catch (NumberFormatException exc) { operand1 = ZERO; operand2 = ZERO; operator = "="; } char c=operator.charAt(0); if (c == '\u00d7') operator="x"; if (c == '*') operator = "x"; if (c == '\u00f7') operator="/"; if (operator.equalsIgnoreCase("=")) { operand1 = operand2; } if (operator.equalsIgnoreCase("+")) { operand1 = operand1.add(operand2); } if (operator.equalsIgnoreCase("-")) { operand1 = operand1.subtract(operand2); } if (operator.equalsIgnoreCase("x")) { operand1 = operand1.multiply(operand2); } if (operator.equalsIgnoreCase("/")) { if (operand2.signum()!=0) { operand1 = operand1.divide(operand2,digits,RHU); } } if (operator.equalsIgnoreCase("x^y")) { operand1 = pow(operand1,operand2); } if (operator.equalsIgnoreCase("rootn")) { operand1 = rootn(operand1,operand2); } display.setText (operand1.toString()); } //-------------------------------------------------------------------- private void unary (String disp, String op) { BigDecimal operand = new BigDecimal(disp); if (op.equalsIgnoreCase("CE/C")||op.equalsIgnoreCase("c")) { operand = ZERO; if (clearButtonFlag) { // second press of CE/C key operand1 = ZERO; operator = "="; } clearButtonFlag = true; } if (op.equalsIgnoreCase("1/x")) { if (operand.signum()!=0) { BigDecimal temp = ONE; operand = temp.divide(operand,digits,RHU); } } if (op.equalsIgnoreCase("+/-")) { operand = operand.negate(); } if (op.equalsIgnoreCase("sqrt")) { if (operand.signum() == 1) { operand = sqrt(operand); } } if (op.equalsIgnoreCase("e^x")) { operand = exp(operand); } if (op.equalsIgnoreCase("ln")) { if (operand.signum() == 1) { operand = ln(operand); } } if (op.equalsIgnoreCase("10^x")) { operand = alog(operand); } if (op.equalsIgnoreCase("log")) { if (operand.signum() == 1) { operand = log(operand); } } if (op.equalsIgnoreCase("x!")) { if (operand.compareTo(ONE.negate()) != -1) { operand = fact(operand); } } if (op.equalsIgnoreCase("R-D")) { degrees = !degrees; if (degrees) { DRG_field.setText("DEG"); } else { DRG_field.setText("RAD"); } } if (op.equalsIgnoreCase("pi")) { operand = pi(); } if (op.equalsIgnoreCase("sin")) { operand = sin(operand); } if (op.equalsIgnoreCase("cos")) { operand = cos(operand); } if (op.equalsIgnoreCase("tan")) { operand = tan(operand); } if (op.equalsIgnoreCase("arcsin")) { operand = arcsin(operand); } if (op.equalsIgnoreCase("arccos")) { operand = arccos(operand); } if (op.equalsIgnoreCase("arctan")) { operand = arctan(operand); } if (op.equalsIgnoreCase("roundoff")) { operand = operand.setScale(digits,RHU); } if (op.startsWith("M")) { int memindx=0; char c = op.charAt(1); // specifies which memory switch (c) { case '1': memindx = 0; break; case '2': memindx = 1; break; case '3': memindx = 2; break; } c = op.charAt(2); // specifies which memory operation switch (c) { case '+': memory[memindx] = memory[memindx].add(operand); break; case '-': memory[memindx] = memory[memindx].subtract(operand); break; case 'R': operand = memory[memindx]; break; case 'C': memory[memindx] = ZERO; break; } } display.setText (operand.toString()); } //-------------------------------------------------------------------- private void light (boolean status) { Graphics g=busy.getGraphics(); Rectangle r=busy.bounds(); int cx = r.width/2; int cy = r.height/2; if (status==true) { g.setColor(Color.red); g.fill3DRect(cx-5,cy-5,10,10,true); } else { g.setColor(Color.darkGray); g.fillRect(cx-5,cy-5,10,10); } } //-------------------------------------------------------------------- private void addButton(Button button, int gridx, int gridy, int gridwidth, int gridheight, Color c) { button.setBackground(c); button.setForeground(Color.black); Graphics g = this.getGraphics(); FontMetrics fm = g.getFontMetrics(); int textwidth = fm.stringWidth(button.getLabel()); int ipadx = (40-textwidth); int ipady = 0; int ext = 5; try { addComponent(this,button,gridx,gridy,gridwidth,gridheight, GridBagConstraints.BOTH,GridBagConstraints.CENTER,ipadx,0,ext); } catch (AWTException e) { System.out.println("AWTException"); e.printStackTrace(); } } //-------------------------------------------------------------------- private static void addComponent(Container container, Component component, int gridx, int gridy, int gridwidth, int gridheight, int fill, int anchor, int ipadx, int ipady, int extpad) throws AWTException { LayoutManager lm = container.getLayout(); if(!(lm instanceof GridBagLayout)) { throw new AWTException ("Invalid layout" + lm); } else { GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = gridx; gbc.gridy = gridy; gbc.weightx = gridx; gbc.weighty = gridy; gbc.gridwidth = gridwidth; gbc.gridheight = gridheight; gbc.fill = fill; gbc.anchor = anchor; gbc.ipadx = ipadx; gbc.ipady = ipady; gbc.insets = new Insets(extpad,extpad,extpad,extpad); ((GridBagLayout)lm).setConstraints(component, gbc); container.add(component); } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- //--------------------- Numerical methods follow --------------------- //-------------------------------------------------------------------- //-------------------------------------------------------------------- private BigDecimal exp (BigDecimal x) { if (breakSignal) return ONE; if (x.signum()==-1) { return ONE.divide(exp(x.negate()),digits,RHU); } BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal n = ZERO; BigDecimal term = ONE; BigDecimal acc_new = ONE; BigDecimal acc_old = ZERO; BigDecimal diff = acc_new.subtract(acc_old); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; acc_old = acc_new; n = n.add(ONE); term = term.multiply(x); term = term.divide(n,digits,RHU); acc_new = acc_new.add(term); diff = term; } return acc_new.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal ln (BigDecimal x){ if (breakSignal) return ONE; if ((x.compareTo(TEN)==0) && (digits<=1000)) { return LN10.setScale(digits,RHU); } if (x.compareTo(ONE)==1) { BigDecimal temp = ONE.divide(x,digits,RHU); temp = ln(temp); return (temp.negate()); } BigDecimal pointnine = new BigDecimal(0.9d); if (x.compareTo(pointnine) == -1) { digits++; BigDecimal temp = sqrt(x); if (breakSignal) return ONE; temp = ln(temp); digits--; temp = temp.add(temp); return (temp.setScale(digits,RHU)); } x = x.subtract(ONE); BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal n = ZERO; BigDecimal term = ONE; BigDecimal powr = ONE; BigDecimal acc_new = ZERO; BigDecimal acc_old = ONE.negate(); BigDecimal diff = term.abs(); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; acc_old=acc_new; n = n.add(ONE); powr = powr.multiply(x); powr = powr.setScale(digits,RHU); term = powr.divide(n,digits,RHU); acc_new = acc_new.add(term); powr = powr.negate(); diff = term.abs(); } return acc_new; } //-------------------------------------------------------------------- private BigDecimal alog (BigDecimal x){ if (x.scale()==0) { // x is an integer, so we can "cheat" return ONE.movePointRight(x.intValue()); } else { BigDecimal temp = x.multiply(LN10); temp = temp.setScale(digits,RHU); return exp(temp); } } //-------------------------------------------------------------------- private BigDecimal log (BigDecimal x){ if (x.compareTo(TEN)==0) { return ONE; } else { return (ln(x)).divide(ln(TEN),digits,RHU); } } //-------------------------------------------------------------------- private BigDecimal pow (BigDecimal x, BigDecimal y){ if (breakSignal) return ONE; if (x.signum() == 0) {return ZERO;} //get x=0 case out of the way if (y.scale()==0) { // if y is an integer, we can "cheat". int yint = y.intValue(); if (yint==0) {return x;} // get y=0 case out of the way BigDecimal product = ONE; BigDecimal multiplier = x; if (yint<0) { multiplier = ONE.divide(multiplier,digits,RHU); yint = -yint; } for (int i=0;i<yint;i++){ if (breakSignal) return ONE; product = product.multiply(multiplier); } return product; } else { if (x.signum()==1) { // require x>0 BigDecimal temp = y.multiply(ln(x)); temp = temp.setScale(digits,RHU); return exp(temp); } } return ZERO; // if thread reaches this point, args were no good. } //-------------------------------------------------------------------- private BigDecimal rootn (BigDecimal x, BigDecimal y){ if (y.signum()==0) return ZERO; // get rid of y=0 case if (y.scale()>0) { // y is not an integer. Send problem to pow(). return pow(x,ONE.divide(y,digits,RHU)); } return rootn(x,y.intValue()); //calls other version of rootn() } //-------------------------------------------------------------------- private BigDecimal rootn (BigDecimal a, int n){ if (breakSignal) return ONE; double double_n = (double)n; BigDecimal bigdec_n = new BigDecimal(double_n); BigDecimal c1 = new BigDecimal(double_n-1); c1 = c1.divide(bigdec_n,digits,RHU); BigDecimal c2 = a.divide(bigdec_n,digits,RHU); // algorithm is: let x = c1*x + c2/(x^powr) // where c1=(n-1)/n, c2=a/n, powr=n-1 BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal xold = ZERO; //xxx just to initialize it BigDecimal xnew = ONE; //xxx 1 is as good a guess as any BigDecimal diff = xnew.subtract(xold); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; xold = xnew; BigDecimal powerofx = ONE; for (int j=0;j<n-1;j++) { if (breakSignal) return ONE; powerofx=powerofx.divide(xold,digits+3,RHU); } xnew = c1.multiply(xold); //first term. xnew = xnew.add(c2.multiply(powerofx)); // second term. diff = xnew.subtract(xold); diff = diff.abs(); } if (breakSignal) return ONE; return xnew.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal sqrt (BigDecimal a){ if (breakSignal) return ONE; // algorithm is: let x = half * ( x + (a/x) ) BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal xold = ZERO; // just to initialize it BigDecimal xnew = ONE; // 1 is as good a guess as any BigDecimal diff = xnew.subtract(xold); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; xold = xnew; xnew = xold.add(a.divide(xold,digits+3,RHU)); // second term. xnew = xnew.divide(TWO,digits+3,RHU); diff = xnew.subtract(xold); diff = diff.abs(); } return xnew.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal fact(BigDecimal n) { // Returns the factorial of a positive real argument n. // If n is not an integer it returns gamma(1+n), which is defined to be // an extension to the factorial from N to R, since for positive integers // n!=gamma(1+n). // The gamma function is not analytic for n=0,-1,-2,-3... and is not // "well-behaved" in the negative real domain, so this method will only // compute the function of arguments greater than -1. if (n.compareTo(ONE.negate())== -1) return ZERO; BigDecimal result = ONE; //xxx while (n.compareTo(ONE)!=-1) { // if not n<1 if (breakSignal) return ONE; result=result.multiply(n); n=n.subtract(ONE); } // at this point we have n less than 1, and result. The argument to // return will be gamma(1+n)*result. If n=0 then gamma(1)=1, so: if (n.signum()==0) return result; // Therefore, now we must find out what gamma(1+n) is. This will not // be ultraprecise no matter what we do, so we might as well use doubles. // The code below computes the natural log of the gamma function using the // Lanczos approximation formula. The gamma function is defined by // ( z - 1 ) -t // gamma( z ) = Integral[ t e dt ] // integrated over the positive real domain. // The gamma function satisfies gamma( n + 1 ) = n! // This algorithm has been adapted from "Numerical Recipes", p. 157. double x = n.doubleValue(); x=x+1; // because it's gamma(x+1) we're getting now double coeff0 = 76.1800917300d; double coeff1 = -86.5053203300d; double coeff2 = 24.0140982200d; double coeff3 = -1.23173951600d; double coeff4 = 1.20858003000E-3d; double coeff5 = -5.36382000000E-6d; double stp = 2.50662827465d; double r = (coeff0/x)+(coeff1/(x+1.0d))+(coeff2/(x+2.0d)) +(coeff3/(x+3.0d))+(coeff4/(x+4.0d))+(coeff5/(x+5.0d)); double s = x+4.5d; double t = (x-0.5d)*Math.log(s) - s; t = Math.exp(t); t *= (stp*(r+1.0d)); double res=1.0d; try { res=result.doubleValue(); res *= t; result = new BigDecimal(res); } catch (NumberFormatException exc) { result = result.multiply(new BigDecimal(t)); return result.setScale(0,RHU); } return result.setScale(10,RHU); } //-------------------------------------------------------------------- private BigDecimal pi() { if (digits<=1000) { return (PI.setScale(digits,RHU)); } else { int extradigits = 3; digits += extradigits; BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal a = ONE; BigDecimal x = ONE; BigDecimal b = ONE; b = b.divide(sqrt(TWO),digits,RHU); BigDecimal c = QUARTER; BigDecimal y = ZERO; BigDecimal pi_old = ZERO; BigDecimal pi_new = ONE; BigDecimal diff = pi_new.subtract(pi_old); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; pi_old = pi_new; y = a; a = a.add(b); a = a.divide(TWO,digits,RHU); // a=(a+b)/2 b = sqrt(b.multiply(y)); // b=sqrt(b*y) pi_new = a.subtract(y); //pi_new is temporarily holding a value c = c.subtract(x.multiply(pi_new.multiply(pi_new))); //c=c-x*(a-y)^2 x = x.add(x); // i.e. x=2*x pi_new = a.add(b); //pi_new is temporarily holding again pi_new = pi_new.multiply(pi_new); y = c.multiply(new BigDecimal(4.0d)); //y is temporarily holding pi_new = pi_new.divide(y,digits,RHU); // pi = (a+b)^2 / (4*c) diff = pi_new.subtract(pi_old); c=c.setScale(digits,RHU); x=x.setScale(digits,RHU); y=y.setScale(digits,RHU); } digits -= extradigits; pi_new = pi_new.setScale(digits,RHU); return pi_new; } } //-------------------------------------------------------------------- private BigDecimal sin (BigDecimal x){ // ensure we're using radians if (degrees) { x = x.multiply(pi()); x = x.divide(ONE_EIGHTY,digits,RHU); } // renormalize to the interval from -pi/2 to pi/2 BigDecimal twopi = pi().multiply(TWO); x = x.divide(twopi,digits,RHU); x = x.subtract(x.setScale(0,BigDecimal.ROUND_DOWN)); //This is the only way to get a fractional part! // interval (-1,1). if (x.compareTo(QUARTER.negate())==-1) { x = x.add(ONE); } // interval [-0.25,1). if (x.compareTo(new BigDecimal(0.75d))!=-1) { x = x.subtract(ONE); } // interval [-0.25,0.75). if (x.compareTo(QUARTER)==1) { x = HALF.subtract(x); } // interval [-0.25,0.25]. x = x.multiply(twopi); // interval [-pi/2,pi/2]. What a pain in the ass... BigDecimal x2 = x.multiply(x); x2 = x2.setScale(digits,RHU); BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal n = ONE; BigDecimal term = x; BigDecimal acc_new = x; BigDecimal acc_old = ZERO; BigDecimal diff = acc_new.subtract(acc_old); diff = diff.abs(); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; acc_old = acc_new; term = term.multiply(x2); n = n.add(ONE); term = term.divide(n,digits,RHU); n = n.add(ONE); term = term.divide(n,digits,RHU); term = term.negate(); acc_new = acc_new.add(term); diff = term.abs(); } return acc_new.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal cos (BigDecimal x){ // could have called sin(pi/2 - x) or something but decided to // compute cosine directly- it's just too easy to cut and paste // and make minor changes. // ensure we're using radians if (degrees) { x = x.multiply(pi()); x = x.divide(ONE_EIGHTY,digits,RHU); } // renormalize to the interval from 0 to pi BigDecimal twopi = pi().multiply(TWO); x = x.divide(twopi,digits,RHU); x = x.subtract(x.setScale(0,BigDecimal.ROUND_DOWN)); // interval (-1,1). if (x.signum()==-1) { x = x.negate(); } // interval [0,1). if (x.compareTo(HALF)!=-1) { x = ONE.subtract(x); } // interval [0,0.5). x = x.multiply(twopi); // interval [0,pi]. BigDecimal x2 = x.multiply(x); x2 = x2.setScale(digits,RHU); BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal n = ZERO; boolean signIsPositive = false; BigDecimal term = ONE; BigDecimal acc_new = ONE; BigDecimal acc_old = ZERO; BigDecimal diff = term.abs(); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; acc_old = acc_new; term = term.multiply(x2); n = n.add(ONE); term = term.divide(n,digits,RHU); n = n.add(ONE); term = term.divide(n,digits,RHU); term = term.negate(); acc_new = acc_new.add(term); diff = term.abs(); } return acc_new.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal tan (BigDecimal x){ BigDecimal s=sin(x); BigDecimal c=sqrt(ONE.subtract(s.multiply(s))); if (breakSignal) return ONE; // Must determine the SIGN of the cos. if (degrees) { x = x.multiply(pi()); x = x.divide(ONE_EIGHTY,digits,RHU); } BigDecimal twopi = pi().multiply(TWO); x = x.divide(twopi,digits,RHU); x = x.subtract(x.setScale(0,BigDecimal.ROUND_DOWN)); if (x.signum()==-1) { x = x.negate(); } if (x.compareTo(HALF)!=-1) { x = ONE.subtract(x); } if (x.compareTo(QUARTER)==1) { c=c.negate(); } if (c.signum()==0) return ZERO; return s.divide(c,digits,RHU); } //-------------------------------------------------------------------- private BigDecimal arcsin (BigDecimal x){ if (breakSignal) return ONE; BigDecimal x2 = x.multiply(x); x2 = x2.setScale(digits,RHU); if(x2.compareTo(ONE)==1) return ZERO; //arcsin domain is [-1,1] if(x2.compareTo(HALF)==1) { // Angle is greater than 45 degrees. Smaller angles work better. // Use identity arcsin(x)=pi/2 - arcsin(sqrt(1-x^2)) BigDecimal temp; if (degrees) { temp = new BigDecimal(90.0d); } else { temp = pi().divide(TWO,digits,RHU); } temp = temp.subtract(arcsin(sqrt(ONE.subtract(x2)))); if (x.signum()==-1) {return temp.negate();} else {return temp;} } BigDecimal smallest = new BigDecimal(UNITY,digits); // 0.000...001 BigDecimal n = ONE; BigDecimal term; BigDecimal powr = x; BigDecimal acc_new = x; BigDecimal acc_old = ZERO; BigDecimal diff = acc_new.subtract(acc_old); BigDecimal oddsOverEvens= ONE; diff = diff.abs(); while (diff.compareTo(smallest)==1) { if (breakSignal) return ONE; acc_old = acc_new; powr = powr.multiply(x2); powr = powr.setScale(digits,RHU); oddsOverEvens=oddsOverEvens.multiply(n); n = n.add(ONE); oddsOverEvens=oddsOverEvens.divide(n,digits,RHU); n = n.add(ONE); term = powr.multiply(oddsOverEvens); term = term.divide(n,digits,RHU); acc_new = acc_new.add(term); diff = term.abs(); } if (degrees) { acc_new = acc_new.multiply(ONE_EIGHTY); acc_new = acc_new.divide(pi(),digits,RHU); } return acc_new.setScale(digits,RHU); } //-------------------------------------------------------------------- private BigDecimal arccos (BigDecimal x){ BigDecimal x2 = x.multiply(x); x2 = x2.setScale(digits,RHU); if(x2.compareTo(ONE)==1) return ZERO; //arccos domain is [-1,1] if (x.signum()==-1) { BigDecimal temp; if (degrees) {temp=ONE_EIGHTY;} else {temp=pi();} return temp.subtract(arcsin(sqrt(ONE.subtract(x2)))); } return arcsin(sqrt(ONE.subtract(x2))); } //-------------------------------------------------------------------- private BigDecimal arctan (BigDecimal x){ BigDecimal x2 = x.multiply(x); x2 = x2.setScale(digits,RHU); return arcsin(x.divide(sqrt(x2.add(ONE)),digits,RHU)); } //-------------------------------------------------------------------- private static BigDecimal set_PI() { // Defines the PI constant to be the 1000 digit approximation of pi. // If precision requires 1000 digits or fewer, the applet can use PI. String piS="3." + "14159265358979323846264338327950288419716939937510" + "58209749445923078164062862089986280348253421170679" + "82148086513282306647093844609550582231725359408128" + "48111745028410270193852110555964462294895493038196" + "44288109756659334461284756482337867831652712019091" + "45648566923460348610454326648213393607260249141273" + "72458700660631558817488152092096282925409171536436" + "78925903600113305305488204665213841469519415116094" + "33057270365759591953092186117381932611793105118548" + "07446237996274956735188575272489122793818301194912" + "98336733624406566430860213949463952247371907021798" + "60943702770539217176293176752384674818467669405132" + "00056812714526356082778577134275778960917363717872" + "14684409012249534301465495853710507922796892589235" + "42019956112129021960864034418159813629774771309960" + "51870721134999999837297804995105973173281609631859" + "50244594553469083026425223082533446850352619311881" + "71010003137838752886587533208381420617177669147303" + "59825349042875546873115956286388235378759375195778" + "18577805321712268066130019278766111959092164201989"; return new BigDecimal(piS); } //-------------------------------------------------------------------- private static BigDecimal set_LN10() { // orignal coding started by www.geocities.com/SiliconValley/2548/BigCalculator.java // Defines the LN10 constant to be the 1000 digit approximation of // the natural log of ten. If precision requires 1000 digits or // fewer, the applet can use LN10 when computing common logarithms. String ln10S="2." + "30258509299404568401799145468436420760110148862877" + "29760333279009675726096773524802359972050895982983" + "41967784042286248633409525465082806756666287369098" + "78168948290720832555468084379989482623319852839350" + "53089653777326288461633662222876982198867465436674" + "74404243274365155048934314939391479619404400222105" + "10171417480036880840126470806855677432162283552201" + "14804663715659121373450747856947683463616792101806" + "44507064800027750268491674655058685693567342067058" + "11364292245544057589257242082413146956890167589402" + "56776311356919292033376587141660230105703089634572" + "07544037084746994016826928280848118428931484852494" + "86448719278096762712757753970276686059524967166741" + "83485704422507197965004714951050492214776567636938" + "66297697952211071826454973477266242570942932258279" + "85025855097852653832076067263171643095059950878075" + "23710333101197857547331541421808427543863591778117" + "05430982748238504564801909561029929182431823752535" + "77097505395651876975103749708886921802051893395072" + "38539205144634197265287286965110862571492198849979"; return new BigDecimal(ln10S); } } |