Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include "basic_math_operations.h" // https://github.com/avighnac/basic_math_operations/blob/main/src/library/basic_math_operations.h
- #include "gcd.hpp"
- #include "lcm.hpp"
- #include <string>
- #include <algorithm>
- #include <map>
- #include <vector>
- class rnumber {
- public:
- std::string number;
- size_t division_accuracy = 20;
- rnumber(std::string s) { number = s; }
- rnumber(const char *s) { number = s; }
- rnumber() {}
- std::string to_string() { return number; }
- void operator=(std::string s) { number = s; }
- void operator=(rnumber n2) { number = n2.number; }
- bool operator==(std::string s) { return number == s; }
- bool operator==(rnumber n2) { return number == n2.number; }
- friend std::ostream &operator<<(std::ostream &os, const rnumber n);
- rnumber operator+(rnumber n) {
- rnumber answer;
- char *buf =
- (char *)calloc(std::max(number.length(), n.number.length()) + 2, 1);
- add(n.number.c_str(), number.c_str(), buf);
- answer.number = buf;
- return answer;
- }
- rnumber operator-(rnumber n) {
- rnumber answer;
- char *buf =
- (char *)calloc(std::max(number.length(), n.number.length()) + 2, 1);
- subtract(number.c_str(), n.number.c_str(), buf);
- answer.number = buf;
- return answer;
- }
- rnumber operator*(rnumber n) {
- rnumber answer;
- char *buf = (char *)calloc(number.length() + n.number.length() + 2, 1);
- multiply(number.c_str(), n.number.c_str(), buf);
- answer.number = buf;
- return answer;
- }
- rnumber operator/(rnumber n) {
- rnumber answer;
- char *buf =
- (char *)calloc(std::max(number.length(), n.number.length()) +
- std::max(division_accuracy, n.division_accuracy) + 3,
- 1);
- divide(number.c_str(), n.number.c_str(), buf,
- std::max(division_accuracy, n.division_accuracy));
- answer.number = buf;
- return answer;
- }
- rnumber operator%(rnumber n) {
- rnumber answer;
- char *buf =
- (char *)calloc(std::max(number.length(), n.number.length()) + 2, 1);
- char *rem =
- (char *)calloc(std::max(number.length(), n.number.length()) + 2, 1);
- divide_whole_with_remainder(number.c_str(), n.number.c_str(), buf, rem);
- answer.number = rem;
- return answer;
- }
- };
- std::ostream &operator<<(std::ostream &os, const rnumber n) {
- os << n.number;
- return os;
- }
- class rfraction {
- public:
- rnumber numerator, denominator;
- rfraction simplify_fraction(rfraction frac) {
- bool negative = false;
- if (frac.numerator.number[0] == '-' && frac.denominator.number[0] == '-') {
- frac.numerator.number =
- frac.numerator.number.substr(1, frac.numerator.number.length());
- frac.denominator.number =
- frac.denominator.number.substr(1, frac.denominator.number.length());
- }
- if (frac.numerator.number[0] == '-' && frac.denominator.number[0] != '-') {
- negative = true;
- frac.numerator.number =
- frac.numerator.number.substr(1, frac.numerator.number.length());
- }
- if (frac.numerator.number[0] != '-' && frac.denominator.number[0] == '-') {
- negative = true;
- frac.denominator.number =
- frac.denominator.number.substr(1, frac.denominator.number.length());
- }
- rnumber GCD = gcd(frac.numerator, frac.denominator);
- size_t t1 = frac.numerator.division_accuracy,
- t2 = frac.denominator.division_accuracy;
- frac.numerator.division_accuracy = 0;
- frac.denominator.division_accuracy = 0;
- frac.numerator = frac.numerator / GCD;
- frac.denominator = frac.denominator / GCD;
- frac.numerator.division_accuracy = t1;
- frac.denominator.division_accuracy = t2;
- if (negative)
- frac.numerator.number = "-" + frac.numerator.number;
- return frac;
- }
- rfraction(std::pair<std::string, std::string> p) {
- numerator = p.first;
- denominator = p.second;
- }
- rfraction(const char *s) {
- std::string str = std::string(s);
- if (str.find('\\') == std::string::npos) {
- if (str.find('/') == std::string::npos) {
- numerator = str;
- denominator = std::string("1");
- } else {
- numerator = str.substr(0, str.find('/'));
- denominator = str.substr(str.find('/') + 1, str.length());
- }
- } else if (str.find("\\frac{") != std::string::npos) {
- numerator = str.substr(str.find("\\frac{") + 6,
- str.find('}') - str.find("\\frac{") - 6);
- denominator = str.substr(str.find("}{") + 2, str.length());
- denominator.number =
- denominator.number.substr(0, denominator.number.length() - 1);
- } else {
- numerator = str;
- denominator = std::string("1");
- }
- }
- rfraction(rnumber r1, rnumber r2) {
- numerator = r1.number;
- denominator = r2.number;
- }
- rfraction() {}
- std::string latex() {
- if (denominator.number != "1")
- return "\\frac{" + numerator.to_string() + "}{" +
- denominator.to_string() + "}";
- else
- return numerator.number;
- }
- std::string to_string() {
- return numerator.to_string() + "/" + denominator.to_string();
- }
- void operator=(std::pair<std::string, std::string> p) {
- numerator = p.first;
- denominator = p.second;
- }
- void operator=(std::string str) {
- if (str.find('\\') == std::string::npos) {
- if (str.find('/') == std::string::npos) {
- numerator = str;
- denominator = std::string("1");
- } else {
- numerator = str.substr(0, str.find('/'));
- denominator = str.substr(str.find('/') + 1, str.length());
- }
- } else if (str.find("\\frac{") != std::string::npos) {
- numerator = str.substr(str.find("\\frac{") + 6,
- str.find('}') - str.find("\\frac{") - 6);
- denominator = str.substr(str.find("}{") + 2, str.length());
- denominator.number =
- denominator.number.substr(0, denominator.number.length() - 1);
- } else {
- numerator = str;
- denominator = std::string("1");
- }
- }
- void operator=(const char *s) {
- std::string str = std::string(s);
- operator=(str);
- }
- void operator=(std::pair<rnumber, rnumber> p) {
- numerator = p.first.number;
- denominator = p.second.number;
- }
- bool operator==(rfraction f2) {
- rfraction new_1 = simplify_fraction(*this);
- rfraction new_2 = simplify_fraction(f2);
- return new_1.numerator == new_2.numerator &&
- new_1.denominator == new_2.denominator;
- }
- friend std::ostream &operator<<(std::ostream &os, const rfraction f);
- rfraction operator+(rfraction f2) {
- rfraction answer = {(numerator * f2.denominator) +
- (denominator * f2.numerator),
- denominator * f2.denominator};
- return simplify_fraction(answer);
- }
- rfraction operator-(rfraction f2) {
- rfraction answer = {(numerator * f2.denominator) -
- (denominator * f2.numerator),
- denominator * f2.denominator};
- return simplify_fraction(answer);
- }
- rfraction operator*(rfraction f2) {
- rfraction answer = {numerator * f2.numerator, denominator * f2.denominator};
- return simplify_fraction(answer);
- }
- rfraction operator/(rfraction f2) {
- std::swap(f2.denominator, f2.numerator);
- rfraction answer = *this * f2;
- return simplify_fraction(answer);
- }
- };
- std::ostream &operator<<(std::ostream &os, const rfraction f) {
- os << f.numerator.number;
- if (f.denominator.number != "1")
- os << std::string("/") << f.denominator.number;
- return os;
- }
- class variable {
- public:
- std::string var;
- rfraction power;
- bool constant = false; // for stuff like sqrt(2)
- bool function = false; // for sin(), log(), arctan(), etc.
- std::string functionName;
- std::string functionValue;
- variable(std::string v, rfraction p) {
- var = v;
- power = p;
- }
- variable(const char *cstr) {
- std::string s = std::string(cstr);
- if (s.find('^') != std::string::npos) {
- var = s.substr(0, s.find('^'));
- std::string rest = s.substr(s.find('^') + 1, s.length());
- if (!rest.empty() && rest[0] == '(')
- power = rest.substr(1, rest.length() - 2);
- else
- power = rest;
- } else {
- var = s;
- power = "1";
- }
- }
- variable() {}
- bool operator==(variable v2) { return var == v2.var && power == v2.power; }
- };
- static std::vector<std::string> split_string(std::string s, char ch) {
- std::vector<std::string> answer;
- std::string part;
- for (auto &i : s) {
- if (i != ch)
- part.push_back(i);
- else {
- answer.push_back(part);
- part.clear();
- }
- }
- answer.push_back(part);
- return answer;
- }
- static void replace_all(std::string &str, const std::string &from,
- const std::string &to) {
- if (from.empty())
- return;
- size_t start_pos = 0;
- while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
- str.replace(start_pos, from.length(), to);
- start_pos += to.length();
- }
- }
- static bool is_letter(char ch) {
- return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
- }
- static size_t get_matching_brace(std::string str, size_t index) {
- if (str[index] != '(')
- return -1;
- int count = 0;
- for (size_t i = index; i < str.length(); i++) {
- if (str[i] == '(')
- count++;
- if (str[i] == ')')
- count--;
- if (!count)
- return i;
- }
- return -1;
- }
- class algnum {
- private:
- static size_t get_matching_open_brace(std::string str, size_t index) {
- if (str[index] != ')')
- return -1;
- int count = 0;
- for (size_t i = index; i + 1 > 0; i--) {
- if (str[i] == '(')
- count--;
- if (str[i] == ')')
- count++;
- if (!count)
- return i;
- }
- return -1;
- }
- static bool
- check_for_functions_behind(std::string input, size_t start_pos,
- std::vector<std::string> &supportedFunctions) {
- for (auto &func : supportedFunctions) {
- if ((long long)start_pos - (long long)func.length() >= 0) {
- if (input.substr(start_pos - func.length(), func.length()) == func) {
- return true;
- }
- }
- }
- return false;
- }
- static size_t prev_index(std::string s, size_t start) {
- if (start == 0)
- return 0;
- for (auto i = start - 1; i + 1 > 0; i--)
- if (s[i] != ' ')
- return i;
- return 0;
- }
- static std::string process_brackets(std::string in, size_t exp_loc,
- size_t &i) {
- if (exp_loc + 1 >= in.length())
- return "";
- // if we have brackets
- if (in[exp_loc + 1] == '(') {
- size_t first_brace_location = exp_loc + 1;
- size_t matching_brace = get_matching_brace(in, first_brace_location);
- i = matching_brace;
- return in.substr(first_brace_location + 1,
- matching_brace - first_brace_location - 1);
- } else {
- if (is_letter(in[exp_loc + 1]))
- return in.substr(exp_loc + 1, 1);
- std::string answer;
- for (auto j = exp_loc + 1; j < in.length(); j++) {
- if (!('0' <= in[j] && in[j] <= '9')) {
- i = j - 1;
- break;
- }
- answer.push_back(in[j]);
- }
- return answer;
- }
- }
- public:
- rfraction constant;
- std::vector<variable> variables;
- void add_variable(variable v) {
- for (auto &i : variables) {
- if (i.var == v.var) {
- i.power = i.power + v.power;
- return;
- }
- }
- variables.push_back(v);
- }
- std::string latex() {
- if (constant.numerator.number == "0")
- return "";
- std::string answer;
- if (constant.numerator.number != constant.denominator.number) {
- if (constant.numerator.number == "-1")
- answer += "-";
- else
- answer += constant.latex();
- if (!variables.empty()) {
- if (!(variables[0].power.denominator.number == "1" ||
- (variables[0].power.numerator.number == "1" &&
- variables[0].power.denominator.number != "1")))
- answer += "\\times";
- }
- }
- for (auto &var : variables) {
- if (var.function) {
- answer += "\\" + var.functionName;
- if (var.power.numerator.number != var.power.denominator.number) {
- if (var.power.denominator.number == "1" &&
- var.power.numerator.number[0] != '-')
- answer += "^" + var.power.latex();
- else
- answer += "^{" + var.power.latex() + "}";
- }
- answer += "{" + var.functionValue + "}";
- } else {
- if (var.power.numerator.number != "1") {
- if (var.var.length() > 1)
- answer += "{" + var.var + "}";
- else
- answer += var.var;
- if (var.power.numerator.number != var.power.denominator.number) {
- if (var.power.denominator.number == "1" &&
- var.power.numerator.number[0] != '-')
- answer += "^" + var.power.latex();
- else
- answer += "^{" + var.power.latex() + "}";
- }
- } else {
- if (var.power.denominator.number == "1")
- answer += var.var;
- else {
- if (var.power.denominator.number == "2")
- answer += "\\sqrt{";
- else
- answer += "\\sqrt[" + var.power.denominator.number + "]{";
- answer += var.var + "}";
- }
- }
- }
- answer += " ";
- }
- if (!variables.empty())
- answer.pop_back();
- return answer;
- }
- algnum(const char *s) {
- std::string input = std::string(s);
- /*
- Functional requirements:
- 1. Identify any brackets ('{}', '()', '[]')
- 2. Detect multiplication indicated by either (x)(y), (x)y, x(y), x*y, or
- just xy.
- 3. Detect some special functions such as sqrt(), cbrt(), sin(), cos(),
- tan(), sec(), cot(), csc() / cosec(), all trig inverse functions such as
- sin^(-1)() which is the same thing as arcsin() which shouldn't be mistaken
- for multiplication, ln(), log_b() should be identified as log to the base
- b, log() (assume base e).
- 4. Detect constants such as 7^(2/5) and assign them as a variable (so they
- only get added with other like constants).
- 5. Detect rational constants in the middle of variables (such as x^2(2)y,
- where 2 is a constant which should be multiplied w/ the already existing
- constant part).
- 6. Detect like terms that have already been made (such as x^2yx, should
- detect the repeated x and not make repeated variables.
- 7. sqrt^2(x), cbrt^2(x), and other obscure function notations should be
- supported.
- Note: tanx should be parsed as tan(x), tanx+2 should be parsed as tan(x) +
- 2, tanx2 should be parsed as 2*tan(x) but tan2x should be parsed as
- tan(2x).
- */
- // Deal with alternative brackets (i.e. anything other than '()')
- replace_all(input, "{", "(");
- replace_all(input, "}", ")");
- replace_all(input, "[", "(");
- replace_all(input, "]", ")");
- // cosec and csc mean the same thing. Also, ln and log without an explicit
- // base also mean the same thing.
- replace_all(input, "cosec", "csc");
- replace_all(input, "ln", "log");
- // Deal with inverse trig. functions
- for (std::string &i :
- std::vector<std::string>{"sin", "cos", "tan", "csc", "sec", "cot"}) {
- replace_all(input, i + "^(-1)", "arc" + i);
- replace_all(input, i + "h^(-1)", "arc" + i + "h"); // Hyperbolic
- }
- // I'm also choosing to ignore all empty brackets (i.e. '()').
- replace_all(input, "()", "");
- // List of supported functions
- std::vector<std::string> supportedFunctions = {"sqrt", "cbrt", "log"};
- for (std::string &i :
- std::vector<std::string>{"sin", "cos", "tan", "csc", "sec", "cot"}) {
- supportedFunctions.push_back(i);
- supportedFunctions.push_back(i + "h");
- supportedFunctions.push_back("arc" + i);
- supportedFunctions.push_back("arc" + i + "h");
- }
- // Now, let's eliminate the problem of variables followed by '-' such as
- // '-y'
- for (auto i = 0; i < input.length() - 1; i++) {
- if (input[i] == '-' && is_letter(input[i + 1])) {
- input = "-1" + input.substr(1, input.length());
- }
- }
- // To deal with the second condition, we can eliminate all brackets that
- // don't enclose the parameters of a function
- size_t start_pos = 0;
- while ((start_pos = input.find('(', start_pos)) != std::string::npos) {
- if (start_pos == 0) {
- input[get_matching_brace(input, 0)] = ' ';
- input[0] = ' ';
- start_pos++;
- continue;
- }
- size_t index_prev_non_space = prev_index(input, start_pos);
- bool can_remove_brackets = input[index_prev_non_space] != '^';
- if (can_remove_brackets) { // only perform this additional
- // check if first one is true
- // check_for_functions() returns true if a function immediately preceeds
- // the bracket start_pos is an index to
- can_remove_brackets =
- !check_for_functions_behind(input, start_pos, supportedFunctions);
- }
- // finally, if it's still true, perform a check for functions' weird power
- // notations i.e. how tan(x)^2 is written as tan^2(x) or x^(2/3) *can* be
- // written as cbrt^2(x)
- if (can_remove_brackets) {
- // this variable contains the index of the first non-space character
- // or 0 if there are no non space characters
- if (start_pos != 0 && input[index_prev_non_space] == ')') {
- size_t matching_brace_pos =
- get_matching_open_brace(input, index_prev_non_space);
- if (input[prev_index(input, matching_brace_pos)] == '_') {
- can_remove_brackets = false;
- }
- if (input[prev_index(input, matching_brace_pos)] == '^') {
- can_remove_brackets = !check_for_functions_behind(
- input, prev_index(input, matching_brace_pos),
- supportedFunctions);
- }
- } else {
- // not ')', check gets a little more complicated
- bool prev_enc_let = false, prev_enc_num = false;
- bool encountering_number = false, encountered_number = false,
- encountered_letter = false;
- for (size_t i = index_prev_non_space; i + 1 > 0; i--) {
- // if two adjacent characters are letters and numbers and stricly
- // that (i.e. num w/ num or letter w/ letter won't work), then no
- // function can possibly be inserted with reference to the bracket
- // pair we're considering, so it's safe to replace it with spaces.
- bool is_current_let = is_letter(input[i]),
- is_current_num = '0' <= input[i] && input[i] <= '9';
- if ((prev_enc_let && is_current_num) ||
- (prev_enc_num && is_current_let))
- break;
- if (is_current_num)
- encountering_number = true;
- if (is_current_let) {
- encountered_letter = true;
- if (encountering_number) {
- encountering_number = false;
- encountered_number = true;
- }
- }
- if (!(encountered_letter && encountered_number)) {
- // can_remove_brackets depends on whether the thing before the
- // exponent is a function in the case of an exponent. you can't
- // remove the brackets in the case of an underscore
- if (input[i] == '_') {
- can_remove_brackets = false;
- break;
- }
- if (input[i] == '^') {
- can_remove_brackets =
- !check_for_functions_behind(input, i, supportedFunctions);
- if (!can_remove_brackets)
- break;
- }
- }
- prev_enc_let = is_current_let;
- prev_enc_num = is_current_num;
- }
- }
- }
- if (can_remove_brackets) {
- input[get_matching_brace(input, start_pos)] =
- ' '; // separate it into parts
- input[start_pos] = ' ';
- }
- start_pos++;
- if (start_pos >= input.length() - 1)
- break;
- }
- replace_all(input, "*", " "); // for 2.
- // Now, remove all subsequent spaces, for example " hell o " -> " hell o "
- while (input.find(" ") != std::string::npos)
- replace_all(input, " ", " ");
- // Deal with each part of the input individually.
- constant = "1"; // since no constant (i.e. x^2y) implies the constant is 1
- auto temp = split_string(input, ' ');
- for (auto &in : temp) {
- for (size_t i = 0; i < in.length(); i++) {
- // check for functions first
- bool functionExists = false;
- std::string functionName;
- for (auto &func : supportedFunctions) {
- if (in.substr(i, func.length()) == func) {
- functionExists = true;
- functionName = func;
- break;
- }
- }
- if (functionExists) {
- std::string varparam;
- rfraction varpower = "1"; // default power
- // deal with functions
- // first, let's deal with the obscure function power notation
- if (in[i + functionName.length()] == '^') {
- size_t powerLocation = i + functionName.length();
- // case with braces is really easy
- if (in[powerLocation + 1] == '(') {
- size_t matching_brace = get_matching_brace(in, powerLocation + 1);
- varpower = in.substr(powerLocation + 2,
- matching_brace - powerLocation - 2);
- size_t next_matching_brace =
- get_matching_brace(in, matching_brace + 1);
- varparam = in.substr(matching_brace + 2,
- get_matching_brace(in, matching_brace + 1) -
- matching_brace - 2);
- i = next_matching_brace;
- } else {
- // this case is also not too bad, we just look ahead for the first
- // '(', that's where our function's parameter is, and will be
- // where the power part ends
- size_t param_brac_begin = in.find('(', i);
- size_t matching_brace = get_matching_brace(in, param_brac_begin);
- varpower = in.substr(powerLocation + 1,
- param_brac_begin - powerLocation - 1);
- varparam = in.substr(param_brac_begin + 1,
- matching_brace - param_brac_begin - 1);
- i = matching_brace;
- }
- } else {
- // we don't need to set the power, default is already 1
- size_t bracket_location = in.find('(', i);
- size_t matching_brace = get_matching_brace(in, bracket_location);
- varparam = in.substr(bracket_location + 1,
- matching_brace - bracket_location - 1);
- i = matching_brace;
- }
- // special functions
- // if varparam doesn't contain any letters, it's a constant
- bool contains_letters = false;
- for (auto &i : varparam) {
- if (is_letter(i)) {
- contains_letters = true;
- break;
- }
- }
- if (functionName == "sqrt") {
- varpower = varpower * "1/2";
- variable v = variable(varparam, varpower);
- v.constant = !contains_letters;
- add_variable(v);
- } else if (functionName == "cbrt") {
- varpower = varpower * "1/3";
- variable v = variable(varparam, varpower);
- v.constant = !contains_letters;
- add_variable(v);
- } else {
- variable v =
- variable(functionName + "(" + varparam + ")", varpower);
- v.function = true;
- v.functionName = functionName;
- v.functionValue = varparam;
- add_variable(v);
- }
- }
- else if (is_letter(in[i])) {
- std::string varname;
- rfraction varpower = "1";
- // we've come across a variable
- size_t variable_begin = i;
- // a variable can either have only a single letter, or a letter
- // followed by a subscript '_' with the subscript either having or not
- // having brackets around it
- // first, let's deal with the subscript variables
- // currently, this code breaks if spaces are used with the
- // subscript variables
- if (variable_begin + 1 < in.length() &&
- in[variable_begin + 1] == '_') {
- size_t subscript_location = variable_begin + 1;
- // if the subscript is enclosed by brackets
- if (subscript_location + 1 < in.length() &&
- in[subscript_location + 1] == '(') {
- size_t first_brace_location = subscript_location + 1;
- size_t matching_brace =
- get_matching_brace(in, first_brace_location);
- varname = in.substr(i, matching_brace - i + 1);
- i = matching_brace + 1;
- } else {
- // the subscript is not enclosed in brackets
- // if the first character of the subscript is a letter, we know
- // that that's where the variable name ends
- if (subscript_location + 1 < in.length() &&
- is_letter(subscript_location + 1)) {
- varname = in.substr(i, subscript_location - i + 2);
- i = subscript_location + 2;
- } else {
- // keep going ahead till a non-numerical character is
- // encountered
- varname = in.substr(i, 2);
- for (auto j = subscript_location + 1; j < in.length(); j++) {
- if (!('0' <= in[j] && in[j] <= '9')) {
- i = j;
- break;
- }
- varname.push_back(in[j]);
- }
- }
- }
- } else {
- // this means we don't have a subscript variable, the variable here
- // is just this singular letter
- varname = in.substr(i, 1);
- i++;
- }
- // now, let's deal with the variables' powers
- // a variable only has a power if the current character (since we
- // incremented i while setting the variable's name) is '^'
- if (i < in.length() && in[i] == '^') {
- size_t powerLocation = i;
- // check for brackets
- if (powerLocation + 1 < in.length() &&
- in[powerLocation + 1] == '(') {
- size_t first_brace_location = powerLocation + 1;
- size_t matching_brace =
- get_matching_brace(in, first_brace_location);
- varpower = in.substr(first_brace_location + 1,
- matching_brace - first_brace_location - 1);
- i = matching_brace;
- } else {
- // we don't have brackets
- // again, only a letter means we're done and that letter is the
- // power
- if (powerLocation + 1 < in.length() &&
- is_letter(in[powerLocation + 1])) {
- varpower = in.substr(powerLocation + 1, 1);
- } else {
- std::string temp;
- // keep going ahead till we encounter the next non-numerical
- // character
- bool did_break = false;
- for (auto j = powerLocation + 1; j < in.length(); j++) {
- if (!('0' <= in[j] && in[j] <= '9')) {
- i = j - 1; // since it's going to be incremented when it
- // loops we have to sub 1
- did_break = true;
- break;
- }
- temp.push_back(in[j]);
- }
- varpower = temp;
- if (!did_break)
- i = powerLocation + temp.length();
- }
- }
- } else {
- if (varname.length() == 1)
- i--; // since we incremented previously for a single letter
- // variable
- }
- add_variable(variable(varname, varpower));
- }
- /*
- 221^(1/3), this is only a variable if it's raised to a power. keep
- checking forward, if you encounter a letter then it's a constant. if you
- encounter ^ before a letter, it's a variable.
- */
- else if (('0' <= in[i] && in[i] <= '9') || in[i] == '-') {
- std::string num;
- // this could either be a constant or a power raised variable
- // (221^(1/3))
- bool did_break = false;
- for (auto j = i; j < in.length(); j++) {
- if (is_letter(in[j])) {
- // is a constant
- i = j - 1;
- constant = constant * rfraction(num.c_str());
- did_break = true;
- break;
- }
- if (in[j] == '^') {
- // is a variable
- std::string power = process_brackets(in, j, i);
- variable v = variable(num, rfraction(power.c_str()));
- v.constant = true;
- add_variable(v);
- did_break = true;
- break;
- }
- num.push_back(in[j]);
- }
- if (!did_break) {
- constant = constant * rfraction(num.c_str());
- i += num.length() - 1;
- }
- }
- }
- }
- // Finally, simplify the constants which have mixed fraction powers
- std::vector<variable> newVariables;
- for (auto i = 0; i < variables.size(); i++) {
- variable &var = variables[i];
- if (var.constant) {
- if ((var.power.numerator - var.power.denominator).to_string()[0] !=
- '-') {
- // if the numerator is greater than or equal to the denominator
- size_t temp1 = var.power.numerator.division_accuracy,
- temp2 = var.power.denominator.division_accuracy;
- var.power.numerator.division_accuracy = 0;
- var.power.denominator.division_accuracy = 0;
- rnumber integerPart = var.power.numerator / var.power.denominator;
- var.power.numerator.division_accuracy = temp1;
- var.power.denominator.division_accuracy = temp2;
- rfraction multiplier = "1";
- rfraction toMultiplyWith = rfraction(var.var.c_str());
- var.power = var.power - rfraction(integerPart, rnumber("1"));
- if (var.power.numerator.number != "0")
- newVariables.push_back(var);
- while (integerPart.number != "0") {
- multiplier = multiplier * toMultiplyWith;
- integerPart = integerPart - "1";
- }
- constant = constant * multiplier;
- } else
- newVariables.push_back(var);
- } else
- newVariables.push_back(var);
- }
- // Remove the raised to 0 variables.
- variables = newVariables;
- }
- algnum() {}
- algnum operator+(algnum a2) {
- // this function only works if both are like
- // it doesn't check this and adds them anyway, be warned.
- algnum answer;
- answer.constant = constant + a2.constant;
- answer.variables = variables;
- return answer;
- }
- algnum operator*(algnum a2) {
- algnum answer;
- answer.constant = constant * a2.constant;
- answer.variables = variables;
- for (auto i = 0; i < a2.variables.size(); i++) {
- long long index = -1;
- for (auto j = 0; j < answer.variables.size(); j++) {
- if (answer.variables[j].var == a2.variables[i].var) {
- index = j;
- break;
- }
- }
- if (index == -1) {
- answer.variables.push_back(a2.variables[i]);
- } else {
- answer.variables[index].power =
- answer.variables[index].power + a2.variables[i].power;
- }
- }
- return answer;
- }
- friend std::ostream &operator<<(std::ostream &os, const algnum n);
- };
- std::ostream &operator<<(std::ostream &os, const algnum n) {
- if (n.variables.empty())
- os << n.constant;
- if (n.constant.numerator.number != n.constant.denominator.number) {
- if (!n.variables.empty())
- os << std::string(" ");
- }
- for (auto i = 0; i < n.variables.size(); i++) {
- os << n.variables[i].var;
- if (n.variables[i].power.numerator.number !=
- n.variables[i].power.denominator.number) {
- os << std::string("^");
- if (n.variables[i].power.denominator.number != "1") {
- os << std::string("(") << n.variables[i].power << std::string(")");
- } else {
- os << n.variables[i].power;
- }
- }
- if (i != n.variables.size() - 1)
- os << std::string(" ");
- }
- return os;
- }
- bool is_like(algnum a, algnum b) {
- for (auto i = 0; i < a.variables.size(); i++) {
- bool found = false;
- for (auto j = 0; j < b.variables.size(); j++) {
- if (a.variables[i] == b.variables[j]) {
- found = true;
- break;
- }
- }
- if (!found)
- return false;
- }
- return true;
- }
- class algexpr {
- private:
- static void clean_double_signs(std::string &expression) {
- while ((expression.find("--") != std::string::npos) ||
- (expression.find("++") != std::string::npos) ||
- (expression.find("-+") != std::string::npos) ||
- (expression.find("+-") != std::string::npos)) {
- replace_all(expression, "--", "+");
- replace_all(expression, "-+", "-");
- replace_all(expression, "+-", "-");
- replace_all(expression, "++", "+");
- }
- replace_all(expression, "*+", "*");
- replace_all(expression, "/+", "/");
- }
- public:
- std::vector<algnum> expr;
- algexpr(const char *s) {
- std::string input = std::string(s);
- clean_double_signs(input);
- replace_all(input, "-", "+-");
- std::vector<std::string> numbers = split_string(input, '+');
- for (auto &i : numbers)
- expr.emplace_back(i.c_str());
- }
- algexpr() {}
- std::string latex() {
- std::string answer;
- for (auto i = 0; i < expr.size(); i++) {
- answer += expr[i].latex();
- if (i + 1 < expr.size()) {
- std::string temp = expr[i + 1].latex();
- if (!temp.empty() && temp[0] != '-')
- answer += "+";
- }
- }
- return answer;
- }
- algnum element(size_t index) { return expr[index]; }
- size_t size() { return expr.size(); }
- void insert(algnum n) { expr.push_back(n); }
- algexpr combine_like_terms(algexpr e) {
- algexpr answer;
- std::vector<size_t> added;
- for (auto i = 0; i < e.size(); i++) {
- if (std::find(added.begin(), added.end(), i) == added.end()) {
- algnum temp = e.element(i);
- for (auto j = i + 1; j < e.size(); j++) {
- if (is_like(temp, e.element(j))) {
- if (std::find(added.begin(), added.end(), j) == added.end()) {
- temp = temp + e.element(j);
- added.push_back(j);
- }
- }
- }
- answer.insert(temp);
- }
- }
- return answer;
- }
- algexpr operator+(algexpr e2) {
- algexpr answer;
- answer.expr = expr;
- for (auto i = 0; i < e2.size(); i++) {
- answer.insert(e2.element(i));
- }
- return combine_like_terms(answer);
- }
- algexpr operator*(algexpr e2) {
- algexpr answer;
- for (auto i = 0; i < e2.size(); i++) {
- for (auto j = 0; j < expr.size(); j++) {
- answer.insert(e2.element(i) * expr[j]);
- }
- }
- return combine_like_terms(answer);
- }
- friend std::ostream &operator<<(std::ostream &os, const algexpr n);
- };
- std::ostream &operator<<(std::ostream &os, const algexpr n) {
- std::string temp;
- if (n.expr.empty())
- return os;
- for (auto i = 0; i < n.expr.size(); i++) {
- if (n.expr[i].constant.numerator.number[0] != '-')
- os << n.expr[i];
- else {
- algnum n1;
- n1.constant = n.expr[i].constant.numerator.number.substr(
- 1, n.expr[i].constant.numerator.number.length());
- n1.variables = n.expr[i].variables;
- os << n1;
- }
- if (i + 1 < n.expr.size()) {
- if (n.expr[i + 1].constant.numerator.number[0] != '-')
- os << std::string(" + ");
- else
- os << std::string(" - ");
- }
- }
- return os;
- }
Advertisement
Add Comment
Please, Sign In to add comment