Commit a9d7a273 authored by Yuanle Song's avatar Yuanle Song
Browse files

add round operator.

add doUnaryOperator() function
parent 2aee6936
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@
	      <td title="sum all numbers in stack" data-bt-name="sum-all">Σ</td>
	      <td title="square root (Q)" data-bt-name="square-root"></td>
	      <td title="power (^)" data-bt-name="power">^</td>
	      <td title="round (R)" data-bt-name="round">ROUND</td>
	      <td title="round (R)" data-bt-name="round">ROND</td>
	    </tr>
	  </table>
	</div>
@@ -439,6 +439,29 @@
	      console.assert(m.numberStack.length === 2);
	      console.assert(m.numberStack[0] === -9);
	      console.assert(m.numberStack[1] === 29 * 2);

	      m.sendKey("backspace");
	      m.sendKey("backspace");    // no number on stack now.

	      // test round, sqrt, power
	      m.sendKey("num1");
	      m.sendKey("dot");
	      m.sendKey("num2");
	      m.sendKey("return");
	      m.sendKey("round");
	      console.assert(m.numberStack.length === 1);
	      console.assert(m.numberStack[0] === 1);

	      m.sendKey("num9");
	      m.sendKey("times");
	      m.sendKey("square-root");
	      console.assert(m.numberStack.length === 1);
	      console.assert(m.numberStack[0] === 3);

	      m.sendKey("num2");
	      m.sendKey("power");
	      console.assert(m.numberStack.length === 1);
	      console.assert(m.numberStack[0] === 9);
	  };
	  const rpnTestBackspaceOperator = function () {
	      const m = new fsm.RPNCalculator();
@@ -799,6 +822,7 @@
		  "^": "power",
		  "Q": "square-root",
		  "U": "undo",
		  "R": "round",
		  // below is not from emacs calc
		  "q": "backspace",
	      };
+50 −23
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ var fsm = function () {
	    undo: "undo",
	    "return": "return",
	    change_sign: "change-sign",
	    round: "round",
	};
	// map keyName to short key name.
	const shortKeyNames = {
@@ -129,6 +130,7 @@ var fsm = function () {
	    "undo": "undo",
	    "return": "ret",
	    "change-sign": "chs",
	    round: "rond",
	};
	const msgTooFewElementsOnStack = "Too few elements on stack";
	const trailHistorySize = 100;
@@ -174,6 +176,39 @@ var fsm = function () {
	this.clearErrorMsg = function () {
	    this.lastError = null;
	};
	/**
	 * do calculator for an unary operator.
	 * this handles not enough element in stack problem.
	 *
	 * it may modify this.numberStack and this.lastError.
	 *
	 * Return true on success, return false on failure.
	 * You may do early return if this function fails. this.lastError will
	 * be set when false is returned.
	 */
	this.doUnaryOperator = function (keyName, func) {
	    this.snapshots.push(this.save());

	    const num = this.numberStack.pop();
	    if (num === undefined) {
		this.setErrorMsg(msgTooFewElementsOnStack);
		this.snapshots.pop();
		return false;
	    }
	    const result = func(num);
	    if (result === undefined || result === null || result === false) {
		// this does consume the number. Just don't push result
		// to number stack.
		if (this.lastError === null) {
		    this.setErrorMsg("result of this operator is undefined or null");
		}
		return false;
	    }
	    this.numberStack.push(result);

	    this.trail.push([shortKeyName(keyName), result]);
	    return true;
	};
	/**
	 * do calculation for a binary operator.
	 * this handles not enough element in stack problem.
@@ -229,7 +264,7 @@ var fsm = function () {
	    keyNames.change_sign,
	    keyNames.plus, keyNames.minus, keyNames.times, keyNames.divide,
	    keyNames.swap, keyNames.undo, keyNames.sum_all, keyNames.square_root,
	    keyNames.power,
	    keyNames.power, keyNames.round,
	];
	const isOperator = function (keyName) {
	    return operatorKeyList.indexOf(keyName) !== -1;
@@ -341,35 +376,27 @@ var fsm = function () {
		} else {
		    switch (keyName) {
		    case keyNames.change_sign:
			this.snapshots.push(this.save());
			num = this.numberStack.pop();
			if (num === undefined) {
			    this.setErrorMsg(msgTooFewElementsOnStack);
			    this.snapshots.pop();
			if (! this.doUnaryOperator(keyName, (num) => -num)) {
			    return;
			}
		    	this.numberStack.push(-num);
			debug("trail push " + [keyName, shortKeyName(keyName), -num]);
			this.trail.push([shortKeyName(keyName), -num]);
		    	break;
		    case keyNames.square_root:
			this.snapshots.push(this.save());
			num = this.numberStack.pop();
			if (num === undefined) {
			    this.setErrorMsg(msgTooFewElementsOnStack);
			    this.snapshots.pop();
		    case keyNames.round:
			if (! this.doUnaryOperator(keyName, (num) => Math.round(num))) {
			    return;
			}
		    	break;
		    case keyNames.square_root:
			if (! this.doUnaryOperator(keyName, (num) => {
			    if (num < 0) {
				// consumes the number and show error to user.
				this.setErrorMsg("square root of negative not supported");
				this.snapshots.pop();
				return;
			    }
			r = Math.pow(num, 0.5);
		    	this.numberStack.push(r);
			debug("trail push " + [keyName, shortKeyName(keyName), r]);
			this.trail.push([shortKeyName(keyName), r]);
			    return Math.pow(num, 0.5);
			})) {
			    return;
			}
		    	break;
		    case keyNames.plus:
			if (! this.doBinaryOperator(keyName, (lhs, rhs) => lhs + rhs)) {
+5 −3
Original line number Diff line number Diff line
@@ -28,16 +28,18 @@ Time-stamp: <2017-01-28>
- update fsm.js keyNames, shortKeyNames, operatorKeyList.
- add operator handling code in fsm.js.

  If you can use this.doBinaryOperator(), use that is easier.
  If you can use this.doUnaryOperator() or this.doBinaryOperator(), use that
  is easier.

  General steps:
  - take snapshot.
  - manipulate numberStack.
  - if there is error, call this.setErrorMsg(), pop snapshot and do early return.
  - if there is no error, push result in numberStack, push new op and result to this.trail.

- add event handler in calc.html.
  set data-bt-name on td.
  if there is a hotkey, handle that hotkey.
  if there is a hotkey, handle that hotkey. just update keyMap map.

** 2017-01-26 design data structure for the calculator.
- this can be written and tested independently from the web UI.
@@ -127,7 +129,6 @@ the parent DOM.

* current                                                             :entry:
** 
** 2017-01-28 add a round operator.
** 2017-01-27 add some visual feedback when clicking a button. like in material design.
** 2017-01-27 UI problem: when input a very large number, #number-display and keyboard will grow.
should set a max-width on #number-display.
@@ -135,6 +136,7 @@ should set a max-width on #number-display.
overflow: auto
doesn't work with <td> in firefox.
* done                                                                :entry:
** 2017-01-28 add a round operator.
** 2017-01-28 try it on mate8.
I can transfer files using bluetooth.