mplekunov / CalculatorApp

GNU General Public License v3.0
1 stars 0 forks source link

New Functions and Constants #24

Closed mplekunov closed 2 years ago

mplekunov commented 2 years ago
  1. Add support for functions that are currently available in "expanded layout"
  2. Add support for constants that are currently available in "expanded layout"
  3. Add support for Brackets
mplekunov commented 2 years ago

Let's start from here for today

mplekunov commented 2 years ago

So,... The ideas...

When it comes to functions, it's important to understand that all of them are in the format of "f(x)"... From this format we can see that we have function name - "f", function parameter - "x" and two parentheses which enclose function parameter

mplekunov commented 2 years ago

Those parentheses aren't the same as "Operator Parentheses"... they just denote the beginning and end of the space allocated for function parameter

mplekunov commented 2 years ago

function parameter can be either a single number or an expression (presumably it can contain another function...)

mplekunov commented 2 years ago

Ideally, I want to preserve my current algo... That is, I want to still use postfix->result algo....

mplekunov commented 2 years ago

So, the whole "function to regular expression" transition should happen before postfix reached evaluator algo... Which means I will have to do that in Postfix class?!

mplekunov commented 2 years ago

Now, after taking a quick look... it looks like I wasn't too tired when I was writing Postfix class lmao... and it looks like it's not going to be too hard to implement functions there... One note, it looks like the best option for "conversion" of some functions would be the recursion...

Like, for example... if we are talking about ln(x)... Single natural log is just a natural log of x... however, when we have ln(ln(x))... this means we will have to process ln(x) first, then return value to the parent ln() and then parent ln returns value in the number format to postfix.

mplekunov commented 2 years ago

So, currently, I want to implement those functions:

Ln Log Sqrt x! x^2 x^y

I think power is a "function" as I plan to allow usage of power on complex expressions such as (ln (2 + ln(10 * sqrt(3))))^3

mplekunov commented 2 years ago

Constants are no brainer... They are just constants

mplekunov commented 2 years ago

As for parentheses (operator parentheses)... I think I can just "add" them to the Operators and everything should work by default as postfix->result algo already have support for parentheses

mplekunov commented 2 years ago

Just thought about natural log... ln(y) = x <==> log_e (y) = x <==> e^x = y which means I can translate it to the simple expression lol

mplekunov commented 2 years ago

But no one would want to read my shit mathematics in the code... especially when there is a library function available lmao... So it's better to stick to Kotlin API 🤣

mplekunov commented 2 years ago

WAIT.... I think I missed something important... If x can be an expression it means I will have to evaluate it as an expression..... Which means I will have to call ExpressionEvaluator.... Inside of the Postfix?!

mplekunov commented 2 years ago

Ok, on the second thought, even though it looks strange it does align with my initial plan of using recursion....

So now the idea is:

when you encounter function in the expression, find where this function ends... then take that sublist and send it back to the ExpressionEvaluator... Expression Evaluator will either do a recursion until it reaches the point when it can return value or return value immediately ... Now when I receive that value, I use log() to get a result of that value, put it on the place where sublist + function name should have been and evaluate expression further.

mplekunov commented 2 years ago

Seems like a plan

mplekunov commented 2 years ago

Sooo... The next several days will be spent on writing test cases and looking at different ways my "parenthesis" implementation can go wrong.... I need to fix all those problems.... Then I will need to implement evaluation of one function with parenthesis (like ln())... After that I need to overhaul my Editing Mode.... From what I can see, dynamically adding spans isn't a good way and it could be better to "respan" the whole input on every change.

mplekunov commented 2 years ago

After that I will roll out a new version with at least one function and full support of parentheses 😃

mplekunov commented 2 years ago

Need to remove all rounding everywhere and only add rounding at the final stage... (Maybe inside of token formatter?!)

mplekunov commented 2 years ago

Otherwise it's hard to have consistent rounding everywhere...

mplekunov commented 2 years ago

Both parentheses and function ln are "fully" implemented... at least as far as my test cases allowed me to test them.

mplekunov commented 2 years ago

The next step is to check viewModel class, though I'm pretty sure it's solid and there should not be much to break/change... and after that straight to edit mode.

mplekunov commented 2 years ago

OH JUST REMEMBERED... I haven't implemented removed logic for functions..... Need to change it so when parenthesis that is closed to function is removed, function is also getting deleted....

mplekunov commented 2 years ago

Now, about Edit Mode (otherwise I will forget it tomorrow lol):

The main problem is that right now, my edit mode dynamically change specifically Token that is being replaced/deleted/changed... The problem is that I have to have some pretty complex logic which figures out the position of the previous token in the span string, then it replaces it with the new string and stuff like that...

The downsides are obvious... It's pain in the ass when we try to add functions support to it... Functions are not only going to be represented as "images" (hence ImageSpan instead of StringSpan) but they also have weird quirks... like they have a body (denoted by parentheses) which complicates everything quite significantly...

mplekunov commented 2 years ago

I guess I can simply prohibit user replacing of functions... Like if there is a function, the only thing they will be able to change would be function body...

mplekunov commented 2 years ago

Or... I can just reconsider what I call a "function"

mplekunov commented 2 years ago

If I define a function as something that MUST have a format of f(x) then x^y, %, x!, x^2 are all not functions

mplekunov commented 2 years ago

hence, the only "functions" are sqrt(), log(), and ln()

mplekunov commented 2 years ago

In fact... if it's only those then I can have "editing mode" for functions because they all have the same format... like f(x)

mplekunov commented 2 years ago

Now, the question is... what are those things are then (x^y, %, x!, x^2 )

mplekunov commented 2 years ago

x^2 and x^2 are power operators.... technically.... but they cannot be replaced by your regular operators.... Unless....

x! (factorial) can't be replace by any other operator... it's like a percent sign...

x^2.... It can be replaced by other operators like +/-*....

x^y can technically also be replaced by other operators like +/-*

mplekunov commented 2 years ago

actually... I think I can differentiate between functions... I still think that % is not an operator... and calling it operator is not really correct... it's more like a function because it has an algo which helps calculating it... Same with x! factorial...

The only difference between those functions and your regular functions (f(x)) is that they have a "single digit" body on the left side...

mplekunov commented 2 years ago

So... I over-engineered solution to the problem....

In simple terms, the only thing I have to do is... to make it so when I call replaceSpan on my input, I replace all spans with new ones (thus avoiding a chance of messing up functions that have parentheses)...

as for imageSpan... I think it can be done with current structure... Right now, last commit contains fully working implementation of parentheses and ln function... It doesn't have "Editing logic" but it is not going to be hard to implement anyway.

Tomorrow I will need to rewrite all the logic I added because it's messy right now and I added it just for the sake of testing my "vision"...

mplekunov commented 2 years ago

oh, and for deletion, I just have to test for parenthesis operator... like if the current token to be deleted is an opening parenthesis... then I test if the token BEFORE that parenthesis is a function... If it is, remove both, if it's not remove only parenthesis.

mplekunov commented 2 years ago

So... It turned out I can attach several spans to the same substring of SpannableStringBuilder object... This means I can attach "drawable" ImageSpan and attach Clickable to int. (Which was done in the last commit in Work_In_Progress)

mplekunov commented 2 years ago

Stuff to do...

Fix an issue where the whole thing crashed when ln is the first thing in expression (probably input adapter)

Fix an issue where the whole thing crashed when I had 6 + ln ( ( 65 -66)) (e.g. negative inside of ln which should have returned NaN without any crashes)

Fix an issue where u can't delete imagespan without crashing (input adapter problem)

Come up with an efficient way to get "drawables" of functions to both "ExpandedClickableFunction" and "ExpandedInputAdapter".. maybe delegation? Like how u use "by Lazy()" or something like that

mplekunov commented 2 years ago

and the final...

Add support for replacing functions.... Everything is technically ready, I just need to add logic for another function to test it and write a bit of code in Expanded classes to differentiate between functions with body at the right side and functions with the body at the left side

mplekunov commented 2 years ago

Can't reproduce first issue...

Second issue was related to ln(0) not negative..

mplekunov commented 2 years ago

Deletion of imagespan is not crashing anymore... The problem was inside of Expression... I forgot to commit previous hotfix I did yesterday and I reset head today in the morning lol

mplekunov commented 2 years ago

Tomorrow:

Clean up code... It's a bit of a mess rn.

Implement Log and SquareRoot functions.

Implement Function Editing in Advanced Mode

mplekunov commented 2 years ago

Before adding new functions.... I want to try redo my spanning... I don't like the fact that I have to do ALL the spanning all over again on every spannable change... that's just stupid... My previous "dynamic" solution was technically O(1) and I want to go back to it... I believe it should be possible with a bit of modification.

mplekunov commented 2 years ago

Time for new functions...

mplekunov commented 2 years ago

HOOORAY 🥳 Logarithm, Natural Logarithm, and square root are all now supported

mplekunov commented 2 years ago

Solved in #33