calc.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /**!
  2. *
  3. * Copyright(c) boyce and other contributors.
  4. * MIT Licensed
  5. *
  6. * Authors:
  7. * boyce <boyce.ywr@gmail.com> (http://www.jianshu.com/users/9b5b907d9bce)
  8. */
  9. 'use strict'
  10. const STATE = {
  11. INIT: 0, //初始状态
  12. RESULT: 1, //结果状态
  13. FIRST_UNDOT: 2, //记录第一个操作数,且该操作数没有小数点
  14. FIRST_DOT: 3, //记录第一个操作数,且该操作数有小数点
  15. SECOND_UNDOT: 4, //记录第二个操作数,且该操作数没有小数点
  16. SECOND_DOT: 5 //记录第二个操作数,且该操作数有小数点
  17. }
  18. let curState = STATE.INIT //状态机所在状态
  19. let curResult = 0 //计算结果
  20. let opNum1 = '0' //操作数1
  21. let opNum2 = '' //操作数2
  22. let op = '' //操作符
  23. let displayNum = opNum1 //界面上应当显示的数值
  24. let displayOp = "" //界面上应当显示的操作符
  25. /**
  26. * 重置程序状态
  27. */
  28. function reset() {
  29. curState = STATE.INIT
  30. curResult = 0
  31. opNum1 = '0'
  32. opNum2 = ''
  33. op = ''
  34. }
  35. /**
  36. * 是否为零
  37. */
  38. function isZero(code) {
  39. return code == '0'
  40. }
  41. /**
  42. * 是否数字
  43. */
  44. function isNumber(code) {
  45. return code >= '0' && code <= '9'
  46. }
  47. /**
  48. * 是否操作符
  49. */
  50. function isOperator(code) {
  51. return code == '+' || code == '-'
  52. || code == 'x' || code == '/' || code == '%'
  53. }
  54. /**
  55. * 是否小数点
  56. */
  57. function isDot(code) {
  58. return code == '.'
  59. }
  60. /**
  61. * 是否是等号
  62. */
  63. function isEquel(code) {
  64. return code == '='
  65. }
  66. /**
  67. * 是否清楚
  68. */
  69. function isClear(code) {
  70. return code == 'c'
  71. }
  72. /**
  73. * 是否删除
  74. */
  75. function isDelete(code) {
  76. return code == 'd'
  77. }
  78. /**
  79. * 转换为可现实的操作符
  80. */
  81. function op2Show(code) {
  82. return code == '/' ? '÷' : (code == 'x' ? '×' : code)
  83. }
  84. /**
  85. *
  86. */
  87. function tryAppend(num, code) {
  88. if (num.length < 15) {
  89. num += code
  90. }
  91. return num
  92. }
  93. function tryTrunc(num) {
  94. let str = '' + num
  95. if (str.length > 15) {
  96. str = str.substr(0, 15)
  97. }
  98. return str
  99. }
  100. /**
  101. *
  102. */
  103. function tryDelete() {
  104. if (curState == STATE.SECOND_DOT
  105. || curState == STATE.SECOND_UNDOT) {
  106. if (opNum2.length > 0) {
  107. opNum2 = opNum2.substr(0, opNum2.length - 1)
  108. }
  109. if (opNum2 == '') {
  110. opNum2 = '0'
  111. }
  112. return
  113. } else {
  114. if (opNum1.length > 0 && opNum1 != '0') {
  115. opNum1 = opNum1.substr(0, opNum1.length - 1)
  116. }
  117. if (opNum1 == '') {
  118. opNum1 = '0'
  119. }
  120. return
  121. }
  122. }
  123. function tryCalc() {
  124. let n1 = parseFloat(opNum1)
  125. let n2 = parseFloat(opNum2)
  126. switch (op) {
  127. case '+':
  128. curResult = n1 + n2
  129. break
  130. case '-':
  131. curResult = n1 - n2
  132. break
  133. case 'x':
  134. curResult = n1 * n2
  135. break
  136. case '/':
  137. if (n2 == 0) {
  138. reset()
  139. curResult = 'NaN'
  140. displayOp = ''
  141. } else {
  142. curResult = n1 / n2
  143. }
  144. break
  145. case '%':
  146. if (n2 == 0) {
  147. reset()
  148. curResult = 'NaN'
  149. displayOp = ''
  150. } else {
  151. curResult = n1 % n2
  152. }
  153. break
  154. }
  155. curResult = tryTrunc(curResult)
  156. }
  157. function addOp(code) {
  158. switch (curState) {
  159. case STATE.RESULT:
  160. case STATE.INIT:
  161. if (isNumber(code) && !isZero(code)) {
  162. curState = STATE.FIRST_UNDOT
  163. opNum1 = code
  164. } else if (isDot(code)) {
  165. curState = STATE.FIRST_DOT
  166. opNum1 = '0.'
  167. } else if (isOperator(code)) {
  168. curState = STATE.SECOND_UNDOT
  169. opNum1 = '0'
  170. opNum2 = ''
  171. op = code
  172. }
  173. displayNum = opNum1
  174. displayOp = ''
  175. break
  176. case STATE.FIRST_UNDOT:
  177. displayOp = ''
  178. if (isNumber(code)) {
  179. if (!isZero(opNum1)) {
  180. opNum1 = tryAppend(opNum1, code)
  181. } else {
  182. opNum1 = code
  183. }
  184. } else if (isDot(code)) {
  185. curState = STATE.FIRST_DOT
  186. opNum1 = opNum1 == '' ? '0' : tryAppend(opNum1, '.')
  187. } else if (isDelete(code)) {
  188. tryDelete()
  189. } else if (isOperator(code)) {
  190. curState = STATE.SECOND_UNDOT
  191. op = code
  192. opNum2 = ''
  193. displayOp = op
  194. }
  195. displayNum = opNum1
  196. break
  197. case STATE.FIRST_DOT:
  198. displayOp = ''
  199. if (isNumber(code)) {
  200. opNum1 = tryAppend(opNum1, code)
  201. } else if (isDelete(code)) {
  202. tryDelete()
  203. if (opNum1.indexOf('.') < 0)
  204. curState = STATE.FIRST_UNDOT
  205. } else if (isOperator(code)) {
  206. curState = STATE.SECOND_UNDOT
  207. op = code
  208. opNum2 = ''
  209. displayOp = op
  210. }
  211. displayNum = opNum1
  212. break
  213. case STATE.SECOND_UNDOT:
  214. if (isNumber(code)) {
  215. if (!isZero(opNum2)) {
  216. opNum2 = tryAppend(opNum2, code)
  217. } else {
  218. opNum2 = code
  219. }
  220. displayNum = opNum2
  221. } else if (isDot(code)) {
  222. curState = STATE.SECOND_DOT
  223. opNum2 = opNum2 == '' ? '0' : tryAppend(opNum2, '.')
  224. displayNum = opNum2
  225. } else if (isDelete(code)) {
  226. tryDelete()
  227. displayNum = opNum2
  228. } else if (isOperator(code)) {
  229. if (opNum2 != '') {
  230. //直接计算
  231. tryCalc()
  232. curState = STATE.SECOND_UNDOT
  233. opNum1 = curResult
  234. opNum2 = ''
  235. displayNum = curResult
  236. }
  237. op = code
  238. displayOp = op
  239. } else if (isEquel(code)) {
  240. if (opNum2 != '') {
  241. tryCalc()
  242. curState = STATE.RESULT
  243. opNum1 = '0'
  244. opNum2 = ''
  245. displayNum = curResult
  246. }
  247. op = code
  248. displayOp = op
  249. }
  250. break
  251. case STATE.SECOND_DOT:
  252. if (isNumber(code)) {
  253. opNum2 = tryAppend(opNum2, code)
  254. displayNum = opNum2
  255. } else if (isDelete(code)) {
  256. tryDelete()
  257. if (opNum2.indexOf('.') < 0)
  258. curState = STATE.SECOND_UNDOT
  259. displayNum = opNum2
  260. } else if (isOperator(code)) {
  261. if (opNum2 != '') {
  262. //直接计算
  263. tryCalc()
  264. curState = STATE.SECOND_UNDOT
  265. opNum1 = curResult
  266. opNum2 = ''
  267. displayNum = curResult
  268. }
  269. op = code
  270. displayOp = op
  271. } else if (isEquel(code)) {
  272. if (opNum2 != '') {
  273. tryCalc()
  274. curState = STATE.RESULT
  275. opNum1 = '0'
  276. opNum2 = ''
  277. displayNum = curResult
  278. }
  279. op = code
  280. displayOp = op
  281. }
  282. break
  283. }
  284. if (isClear(code)) {
  285. reset()
  286. displayNum = opNum1
  287. displayOp = ''
  288. }
  289. displayOp = op2Show(displayOp)
  290. }
  291. reset()
  292. module.exports = {
  293. reset, addOp, getVars(){
  294. return {curState, curResult, opNum1, opNum2, op, displayNum, displayOp}
  295. }
  296. }