class ScientificCalculator { constructor(previousOperandTextElement, currentOperandTextElement) { this.previousOperandTextElement = previousOperandTextElement; this.currentOperandTextElement = currentOperandTextElement; this.angleMode = 'DEG'; // DEG or RAD this.shiftMode = false; this.alphaMode = false; this.lastAnswer = null; this.historyListElement = document.getElementById('history-list'); this.clear(); } clear() { this.currentOperand = '0'; this.expression = ''; this.resetScreen = false; this.updateDisplay(); } delete() { if (this.currentOperand === '0' || this.resetScreen) { this.currentOperand = '0'; this.resetScreen = false; return; } this.currentOperand = this.currentOperand.toString().slice(0, -1); if (this.currentOperand === '') this.currentOperand = '0'; this.updateDisplay(); } appendNumber(number) { if (this.resetScreen) { this.currentOperand = number.toString(); this.resetScreen = false; } else { if (this.currentOperand === '0' && number !== '.') { this.currentOperand = number.toString(); } else { this.currentOperand = this.currentOperand.toString() + number.toString(); } } this.updateDisplay(); } appendOperator(operator) { if (this.currentOperand === '' && this.expression === '') return; // Convert current to expression if we have one if (this.currentOperand !== '') { if (this.expression !== '') { this.expression += this.currentOperand; } else { this.expression = this.currentOperand; } this.currentOperand = ''; } // Add operator this.expression += ' ' + operator + ' '; this.updateDisplay(); } appendFunction(func) { if (this.resetScreen) { this.currentOperand = ''; this.resetScreen = false; } if (this.currentOperand === '0') { this.currentOperand = func + '('; } else { this.currentOperand += func + '('; } this.updateDisplay(); } appendConstant(constant) { if (this.resetScreen) { this.currentOperand = ''; this.resetScreen = false; } let value; switch(constant) { case 'pi': value = Math.PI; break; case 'e': value = Math.E; break; default: return; } if (this.currentOperand === '0') { this.currentOperand = value.toString(); } else { this.currentOperand += value.toString(); } this.updateDisplay(); } negate() { if (this.currentOperand === '0') return; if (this.currentOperand.startsWith('-')) { this.currentOperand = this.currentOperand.substring(1); } else { this.currentOperand = '-' + this.currentOperand; } this.updateDisplay(); } toRadians(degrees) { return degrees * (Math.PI / 180); } toDegrees(radians) { return radians * (180 / Math.PI); } computeTrig(func, value) { const radians = this.angleMode === 'DEG' ? this.toRadians(value) : value; switch(func) { case 'sin': return Math.sin(radians); case 'cos': return Math.cos(radians); case 'tan': return Math.tan(radians); default: return NaN; } } computeInverseTrig(func, value) { let result; switch(func) { case 'asin': result = Math.asin(value); break; case 'acos': result = Math.acos(value); break; case 'atan': result = Math.atan(value); break; default: return NaN; } return this.angleMode === 'DEG' ? this.toDegrees(result) : result; } factorial(n) { if (n < 0) return NaN; if (n === 0 || n === 1) return 1; if (n > 170) return Infinity; // Prevent overflow let result = 1; for (let i = 2; i <= n; i++) { result *= i; } return result; } evaluateExpression(expr) { try { // Replace mathematical symbols with JS equivalents let evalExpr = expr .replace(/×/g, '*') .replace(/÷/g, '/') .replace(/−/g, '-') .replace(/sin\(/g, 'Math.sin(') .replace(/cos\(/g, 'Math.cos(') .replace(/tan\(/g, 'Math.tan(') .replace(/log\(/g, 'Math.log10(') .replace(/ln\(/g, 'Math.log(') .replace(/√\(/g, 'Math.sqrt(') .replace(/π/g, Math.PI) .replace(/e(?![x])/g, Math.E); return eval(evalExpr); } catch (e) { return NaN; } } compute() { let fullExpression = this.expression; // Add current operand if exists if (this.currentOperand !== '') { fullExpression += this.currentOperand; } if (fullExpression === '') return; // Handle special functions let result; // Check for standalone trig functions const trigMatch = fullExpression.match(/^(sin|cos|tan)\(([^)]+)\)$/); if (trigMatch) { const value = parseFloat(trigMatch[2]); result = this.computeTrig(trigMatch[1], value); } // Check for square else if (fullExpression.startsWith('x²(')) { const value = parseFloat(fullExpression.slice(4, -1)); result = value * value; } // Check for cube else if (fullExpression.startsWith('x³(')) { const value = parseFloat(fullExpression.slice(4, -1)); result = value * value * value; } // Check for square root else if (fullExpression.startsWith('√(')) { const value = parseFloat(fullExpression.slice(3, -1)); result = Math.sqrt(value); } // Check for power (x^y format) else if (fullExpression.includes('^')) { const parts = fullExpression.split('^'); const base = parseFloat(parts[0]); const exponent = parseFloat(parts[1]); result = Math.pow(base, exponent); } // Check for factorial else if (fullExpression.startsWith('x!(')) { const value = parseFloat(fullExpression.slice(4, -1)); result = this.factorial(value); } // Check for log else if (fullExpression.startsWith('log(')) { const value = parseFloat(fullExpression.slice(5, -1)); result = Math.log10(value); } // Check for natural log else if (fullExpression.startsWith('ln(')) { const value = parseFloat(fullExpression.slice(4, -1)); result = Math.log(value); } // Check for absolute value else if (fullExpression.startsWith('Abs(')) { const value = parseFloat(fullExpression.slice(5, -1)); result = Math.abs(value); } // Check for power of 10 else if (fullExpression.startsWith('10^')) { const value = parseFloat(fullExpression.slice(4)); result = Math.pow(10, value); } // Check for exponential (e^x) else if (fullExpression.startsWith('e^')) { const value = parseFloat(fullExpression.slice(3)); result = Math.exp(value); } // Regular expression evaluation else { result = this.evaluateExpression(fullExpression); } // Handle precision if (!isNaN(result) && isFinite(result)) { result = Math.round(result * 1000000000000) / 1000000000000; // Add to history this.addToHistory(fullExpression, result); this.lastAnswer = result; this.currentOperand = result.toString(); this.expression = ''; this.resetScreen = true; } else { this.currentOperand = 'Error'; this.resetScreen = true; } this.updateDisplay(); } updateDisplay() { let displayValue = this.currentOperand || '0'; // Truncate if too long if (displayValue.length > 15) { const num = parseFloat(displayValue); if (!isNaN(num)) { displayValue = num.toExponential(6); } else { displayValue = displayValue.substring(0, 15); } } this.currentOperandTextElement.innerText = displayValue; this.previousOperandTextElement.innerText = this.expression; } addToHistory(expression, result) { const historyContainer = document.getElementById('history-list'); if (historyContainer.querySelector('.italic')) { historyContainer.innerHTML = ''; } const historyItem = document.createElement('div'); historyItem.className = 'history-item'; historyItem.innerHTML = `