공학용 계산기 만들기 - boostcamp-2020/Project15-C-Client-Based-Formula-Editor GitHub Wiki

Feature

  • ANS : 이전 결과값 이용 버튼
  • C : clear
  • remove : 한 글자씩 지우기
  • Rad/Deg : 라디안 단위 , 각도 단위
    • Rad : cos(pie) = -1
    • Deg : cos(180) = -1
  • power : 제곱, Math.pow(base, exponent)

버튼

01. 형태

  • 각 버튼들은 객체형태이다.
{
	name: rad, button element 생성시 id 값으로 들어감
	symbol: Rad, button에 보여질 내용 및 operation에 보여질 내용 
	formula: false, 백그라운드에서 실제 계산될 때 사용될 내용 (JS 코드)
	type: key, button의 타입을 분류
}
  • formula는 false or empty string or nothing
  • type은 key, math_function, number, trigo_function, operator, calculate(=)
  • trigonometric : 삼각법, inverse trigonometric : 역삼각법

02. 이벤트

  • 부모 div 붙인 하나의 이벤트 리스너로 동작
  • event.target으로부터 id값을 읽어와서 caclulator_buttons 라는 객체 배열에서 반복문을 통해서 객체를 찾는다.
  • 객체({name, symbol, formula, type})를 찾았으면 그 객체를 calculator 함수의 매개변수로 전달한다.

03. calculator 함수

  • type은 총 6개
  • number, operator, math_function, trigo_function, key, calculate
  • number → operationArray.push(symbol), formulaArray.push(formula)
  • operator, math_function, trigo_function(little different) → number와 동일
  • key → Rad, Deg, C, Remove
  • operationArray = [4, 5, "-", "cos(", 5, 0, ")", "+", "pie"] (symbol들 저장)
  • operationArray.join('') = "45-cos(50)+pie" (화면에 츨력)
  • formulaArray = [4, 5, "-", "Math.cos(", 5, 0, ")", "+", "Math.PI"] (formula들 저장)
  • formulaArray.join('') = "45-Math.cos(50)+Math.pI" (eval 함수를 호출한다.)

The eval() function evaluates JavaScript code represented as a string eval 함수는 문자열로 표현된 JS 코드를 계산하는 함수이다. ex. eval("alert('key')"); ⇒ 알림창을 띄운다.

  • "45-Math.cos(50)+Math.pI" 문자열을 eval 함수를 실행해 JS 코드로 계산한다. 그리고 (화면에 출력)
  • operationArray와 formulaArray는 항상 동기화되어야 한다.

04. calculator 함수 : math_function (factorial)

image image

  • Math.pow는 built-in function이지만 factorial은 만들어야 한다.
function factorial(num){
	if(num % 1 !== 0) return gamma(num + 1); // +1은 gamma func의 사용법
	// 정수는 1로 나눈 나머지가 0이지만 소수는 1로 나눈 나머지가 0이 아니니까
	// 이 방식으로 소수를 검출하고 소수는 gamma func으로 해결한다.
	if(num === 0 || num === 1) return 1;
	let result = 1;
	for(let i=1; i<=num; i++){
		result = result * i;
		if(resuslt === Infinity) return Infinity;
	}
	return result;
}

image


05. Fix : factorial, power

image

  • Factorial

image

  • factorial을 찾고, 있으면 factorial 앞의 숫자를 가져온다. factorialNumberGetter는 2를 return 할 것이다. 그리고 모양이 factorial(2)로 바뀌어야 한다.
  • formula_str에서 replace 함수를 호출한다. 이때 factorial 앞의 모든 숫자, toReplace, repacement 이렇게 3가지가 필요하다.
  • Power

image

  • factorial과 마찬가지 power 앞의 숫자를 가져온다. powerBaseGetter는 4를 return 할 것이다.
  • 위 두함수를 통해 아래의 결과를 만들어낼 것이다.

image


06. Fix : Power

image

// data.formula === formulaArray
const POWER = "POWER(";
let POWER_SEARCH_RESULT = search(formulaArray, POWER); // [3, 17];
function search(array, keyword) {
	let result_array = [];
	array.forEach(element, index) => {
		if(keyword === element) result_array.push(index);
	});
	return result_array;
}
  • powerBaseGetter

image

  • 모든 bases를 찾아서 리턴한다. (powers_bases 배열에 담아서)
  • power index의 바로 앞(-1)부터가 base의 마지막 index이다. 거기서 시작해서 맨 앞까지 가면서 base를 찾는다. (index를 1씩 줄여가면서)
  • formula 는 formulaArray와 동일하게 봐도 된다. 사용자가 입력한 모든 formula가 들어있는 배열
  • push 말고 unshift를 쓴다. 이유는 뒤에서부터 앞으로 탐색을 하기 때문이다.
  • unshift() 메서드는 새로운 요소를 배열의 맨 앞쪽에 추가하고, 새로운 길이를 반환합니다.
  • 앞방향으로 탐색을 해나가다가 operator일 경우 break 한다.
  • parentheses(괄호)를 세다가 여는 괄호와 닫는 괄호가 같을 경우 break 한다. (위 조건과 묶는다.)
  • 5 POWER( 6 POWER 2 ) ) 인 경우도 있다. 그래서 power( 인 경우에도 break를 한다.
  • base를 ('')로 join하고 powers_bases에 담는다.
  • replace

image

  • powerBaseGetter 함수를 통해 얻은 bases를 이용해서 JS 형식에 맞게 replace 해준다.

07 Fix : Factorial

image

// data.formula === formulaArray
cosnt FACTORIAL = "FACTORIAL:
let FACTORIAL_SEARCH_RESULT = search(formulaArray, FACTORIAL);
// [3, 8, 9, 10]
  • factorialNumberGetter

image

  • powerBaseGetter랑은 다르게 이전 index가 아닌 다음 index를 먼저 검사한다. 다음 index가 factorial인지 검사를 진행한다.
  • index 8을 먼저 검사해보면 다음 index가 factorial이다. 이럴 떄는 factorial_sequence를 증가시키고 for loop를 끝낸다. index 9으로 가서 똑같이 진행하고 index 10으로 간다.
  • index 10은 마지막 factorial이므로 연속된 factorial 중에서 가장 처음 factorial의 index 값을 구한다. (factorial_sequence를 빼는 방법을 통해서)
  • 그리고 가장 처음 factorial의 index에 -1을 한 값을 가지고 다시 반복문을 돈다.

image

  • powerBaseGetter 처럼 한 개씩 담아가면서 맨 앞 index로 이동한다.
  • 마찬가지로 앞으로 탐색하다가 operator일 경우 break;
  • 여는 괄호와 닫는 괄호가 같은 경우 break;
  • 이렇게 factorial의 모든 number를 구했으면 join한다.
  • factorial_sequence에 + 1 을 해서 factorial 의 반복 개수를 구한다. (times)
  • !!!, 3번 factorial이 반복되는 경우 factorial_sequence 는 2이므로 1을 더하는 것이다.
  • factorial_sequence를 이용해서 toReplace 값과 replacement 값을 구한다.
  • 그리고 factorial_sequence는 매번 0으로 초기화해줘야 한다.

image

  • replace를 진행해준다.

08. ANGLE UNIT

image

  • JS의 Math의 삼각함수를 사용할 때는 degree가 아닌 radian이 default이다.
  • 즉 Math.cos(매개변수(ex.180) : radian 값이 들어간다.)
  • 그리고 inverse 삼각함수는 radian 값을 리턴한다.

image

  • 1deg는 pie rad / 180이다.

image

  • rad, deg 버튼에 따라서 radian 값이 토글된다.
trigo(Math.cos, 180);

function trigo( callback, angle){
	if(!RADIAN){ // Degree인 경우 Math.PI/180을 곱해서 degree 값으로 변환
		angle = angle * Math.PI/180;
	}
	return callback(angle);
}

image

function inv_trigo(callback, value){
	let angle = callback(value);
	if(!RADIAN){ // Degree인 경우 180/Math.PI를 곱해서 degree 값으로 변환
		angle = angle * 180/Math.PI;
	}
	return angle
}