#include <Arduino.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
// Token tipleri
enum TokenType {
TOKEN_NUMBER,
TOKEN_OPERATOR,
TOKEN_FUNCTION,
TOKEN_CONSTANT,
TOKEN_NONE
};
// Token yapısı
struct Token {
TokenType type;
char op; // Operatör için
char func[10]; // Fonksiyon için (isim)
double value; // Sayı değeri
};
// Global: radyan/derece modu
bool useRadians = true;
// Önecelik fonksiyonu
int precedence(char op) {
switch(op) {
case '+': case '-': return 1;
case '*': case '/': case '%': return 2;
case '^': return 3;
case '!': return 4; // faktöriyel postfix için
}
return 0;
}
bool isRightAssociative(char op) {
return (op == '^' || op == '!');
}
// Fonksiyonları kontrol eder (sadece bazıları örnek)
bool isFunction(const char *str, int len) {
const char* funcs[] = {
"sin", "cos", "tan",
"asin", "acos", "atan",
"sinh", "cosh", "tanh",
"asinh", "acosh", "atanh",
"ln", "log", "exp", "sqrt",
"antilog"
};
for (int i=0; i < sizeof(funcs)/sizeof(funcs[0]); i++) {
if (strlen(funcs[i]) == len && strncmp(funcs[i], str, len) == 0) return true;
}
return false;
}
// Constants
double getConstant(const char *str) {
if (strcmp(str, "pi") == 0) return 3.14159265358979323846;
if (strcmp(str, "e") == 0) return 2.71828182845904523536;
return NAN;
}
// Dönüşüm: derece <-> radyan
double convertToRadians(double val) {
return useRadians ? val : val * (M_PI / 180.0);
}
double convertToDegrees(double val) {
return useRadians ? val : val * (180.0 / M_PI);
}
// Güvenli üs alma (integer üs için hızlı)
double fastPow(double base, int exp) {
double result = 1.0;
int e = abs(exp);
while (e > 0) {
if (e & 1) result *= base;
base *= base;
e >>= 1;
}
return exp >= 0 ? result : 1.0/result;
}
// Faktöriyel (iteratif)
double factorial(double n) {
if (n < 0) return NAN;
if (n == 0) return 1;
double f = 1;
for (int i=1; i <= (int)n; i++) f *= i;
return f;
}
// Tokenize fonksiyonu (basit hali)
int tokenize(const char *expr, Token tokens[], int maxTokens) {
int pos = 0;
int count = 0;
while(expr[pos] != '\0' && count < maxTokens) {
if (isspace(expr[pos])) {
pos++;
continue;
}
// Sayı okuma (integer veya ondalık)
if (isdigit(expr[pos]) || expr[pos] == '.') {
char buffer[20];
int bpos = 0;
while((isdigit(expr[pos]) || expr[pos] == '.') && bpos < 19) {
buffer[bpos++] = expr[pos++];
}
buffer[bpos] = '\0';
tokens[count].type = TOKEN_NUMBER;
tokens[count].value = atof(buffer);
count++;
continue;
}
// Operatörler
if (strchr("+-*/%^!()", expr[pos]) != NULL) {
tokens[count].type = TOKEN_OPERATOR;
tokens[count].op = expr[pos++];
count++;
continue;
}
// Harfli ifadeler (fonksiyon, sabit)
if (isalpha(expr[pos])) {
char buffer[10];
int bpos = 0;
while ((isalpha(expr[pos]) || isdigit(expr[pos])) && bpos < 9) {
buffer[bpos++] = expr[pos++];
}
buffer[bpos] = '\0';
if (isFunction(buffer, bpos)) {
tokens[count].type = TOKEN_FUNCTION;
strncpy(tokens[count].func, buffer, 10);
} else {
double cval = getConstant(buffer);
if (!isnan(cval)) {
tokens[count].type = TOKEN_CONSTANT;
tokens[count].value = cval;
} else {
// Bilinmeyen, hata
return -1;
}
}
count++;
continue;
}
// Bilinmeyen karakter
return -1;
}
return count;
}
// Yığıt (stack) yapıları ve fonksiyonlar
struct TokenStack {
Token data[64];
int top;
void init() { top = -1; }
bool empty() { return top == -1; }
bool push(Token t) {
if (top >= 63) return false;
data[++top] = t;
return true;
}
Token pop() {
if (empty()) return Token{TOKEN_NONE, 0, "", NAN};
return data[top--];
}
Token peek() {
if (empty()) return Token{TOKEN_NONE, 0, "", NAN};
return data[top];
}
};
// Infix->Postfix dönüşümü (Shunting-yard)
int infixToPostfix(Token infixTokens[], int infixCount, Token postfixTokens[], int maxPostfix) {
TokenStack opStack;
opStack.init();
int pcount = 0;
for (int i=0; i < infixCount; i++) {
Token t = infixTokens[i];
if (t.type == TOKEN_NUMBER || t.type == TOKEN_CONSTANT) {
if (pcount >= maxPostfix) return -1;
postfixTokens[pcount++] = t;
} else if (t.type == TOKEN_FUNCTION) {
opStack.push(t);
} else if (t.type == TOKEN_OPERATOR) {
if (t.op == '(') {
opStack.push(t);
} else if (t.op == ')') {
// Parantez kapama, açana kadar çıkar
bool foundLeft = false;
while (!opStack.empty()) {
Token top = opStack.pop();
if (top.type == TOKEN_OPERATOR && top.op == '(') {
foundLeft = true;
break;
} else {
if (pcount >= maxPostfix) return -1;
postfixTokens[pcount++] = top;
}
}
if (!foundLeft) return -1; // Eşleşmeyen parantez
// Eğer üstte fonksiyon varsa postfix'e koy
if (!opStack.empty() && opStack.peek().type == TOKEN_FUNCTION) {
Token f = opStack.pop();
if (pcount >= maxPostfix) return -1;
postfixTokens[pcount++] = f;
}
} else {
// Operatörler için öncelik kontrolü
while (!opStack.empty()) {
Token top = opStack.peek();
if (top.type == TOKEN_OPERATOR &&
((precedence(top.op) > precedence(t.op)) ||
(precedence(top.op) == precedence(t.op) && !isRightAssociative(t.op))) &&
top.op != '(') {
if (pcount >= maxPostfix) return -1;
postfixTokens[pcount++] = opStack.pop();
} else {
break;
}
}
opStack.push(t);
}
}
}
// Kalanları boşalt
while (!opStack.empty()) {
Token top = opStack.pop();
if (top.type == TOKEN_OPERATOR && (top.op == '(' || top.op == ')')) return -1;
if (pcount >= maxPostfix) return -1;
postfixTokens[pcount++] = top;
}
return pcount;
}
// Fonksiyonları hesapla
double evaluateFunction(const char *func, double arg) {
if (strcmp(func, "sin") == 0) return sin(convertToRadians(arg));
if (strcmp(func, "cos") == 0) return cos(convertToRadians(arg));
if (strcmp(func, "tan") == 0) return tan(convertToRadians(arg));
if (strcmp(func, "asin") == 0) return convertToDegrees(asin(arg));
if (strcmp(func, "acos") == 0) return convertToDegrees(acos(arg));
if (strcmp(func, "atan") == 0) return convertToDegrees(atan(arg));
if (strcmp(func, "sinh") == 0) return sinh(arg);
if (strcmp(func, "cosh") == 0) return cosh(arg);
if (strcmp(func, "tanh") == 0) return tanh(arg);
if (strcmp(func, "asinh") == 0) return asinh(arg);
if (strcmp(func, "acosh") == 0) return acosh(arg);
if (strcmp(func, "atanh") == 0) return atanh(arg);
if (strcmp(func, "ln") == 0) return log(arg);
if (strcmp(func, "log") == 0) return log10(arg);
if (strcmp(func, "exp") == 0) return exp(arg);
if (strcmp(func, "antilog") == 0) return pow(10, arg);
if (strcmp(func, "sqrt") == 0) return sqrt(arg);
return NAN;
}
// Postfix değerlendirme
double evaluatePostfix(Token postfixTokens[], int count) {
double stack[64];
int top = -1;
for (int i=0; i<count; i++) {
Token t = postfixTokens[i];
if (t.type == TOKEN_NUMBER || t.type == TOKEN_CONSTANT) {
stack[++top] = t.value;
} else if (t.type == TOKEN_FUNCTION) {
if (top < 0) return NAN;
double val = stack[top--];
double res = evaluateFunction(t.func, val);
if (isnan(res)) return NAN;
stack[++top] = res;
} else if (t.type == TOKEN_OPERATOR) {
if (t.op == '!') {
if (top < 0) return NAN;
double val = stack[top--];
double res = factorial(val);
if (isnan(res)) return NAN;
stack[++top] = res;
} else {
if (top < 1) return NAN;
double b = stack[top--];
double a = stack[top--];
double res = NAN;
switch(t.op) {
case '+': res = a + b; break;
case '-': res = a - b; break;
case '*': res = a * b; break;
case '/': if (b == 0) return NAN; else res = a / b; break;
case '%': if (b == 0) return NAN; else res = fmod(a,b); break;
case '^': res = fastPow(a, (int)b); break;
}
if (isnan(res)) return NAN;
stack[++top] = res;
}
}
}
if (top != 0) return NAN; // Fazla operatör ya da operand var
return stack[top];
}
// --- Main sketch ---
char expr[120];
int exprIdx = 0;
void setup() {
Serial.begin(115200);
while(!Serial);
Serial.println(F("Scientific Calculator"));
Serial.println(F("Choose mode: (r)adian or (d)egree:"));
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if ((exprIdx == 0) && (c == 'r' || c == 'R' || c == 'd' || c == 'D')) {
useRadians = (c == 'r' || c == 'R');
Serial.print(F("Mode set to "));
Serial.println(useRadians ? F("Radians") : F("Degrees"));
Serial.println(F("Enter expression:"));
return;
}
if (c == '\n' || c == '\r') {
expr[exprIdx] = '\0';
if (exprIdx == 0) {
// Boş satır
Serial.println(F("Enter expression:"));
return;
}
Token tokens[64];
int tokCount = tokenize(expr, tokens, 64);
if (tokCount < 0) {
Serial.println(F("Error tokenizing expression!"));
exprIdx = 0;
Serial.println(F("Enter expression:"));
return;
}
Token postfix[64];
int postfixCount = infixToPostfix(tokens, tokCount, postfix, 64);
if (postfixCount < 0) {
Serial.println(F("Error converting to postfix! Check parentheses."));
exprIdx = 0;
Serial.println(F("Enter expression:"));
return;
}
double result = evaluatePostfix(postfix, postfixCount);
if (isnan(result)) {
Serial.println(F("Error evaluating expression!"));
exprIdx = 0;
Serial.println(F("Enter expression:"));
return;
}
Serial.print(F("Expression: "));
Serial.println(expr);
Serial.print(F("Result: "));
Serial.println(result, 15);
Serial.println(F("Enter expression:"));
// İfadeyi silme, seri monitörde kalacak
exprIdx = 0;
} else {
if (exprIdx < (int)(sizeof(expr) - 1)) {
expr[exprIdx++] = c;
}
}
}
}