Adding a log function to the java calculator program - java

I am building a personal scientific calculator. I need help to add the long function into the program with the compiler giving only one answer throughout program. At which part of the if-statement should I add the method?
I am a beginner by the way and this is one of the first projects I am working on.
public void OperatorIndicator(double x, double y, String op){
if (op == "*") {
multiply(x, y);
} else if (op == "/") {
divide(x, y);
} else if (op == "+") {
sum(x, y);
} else if (op == "-") {
difference(x, y);
} else if (op == ""){
if (y == 0) {
squareroot(x);
} else {
exponent(x,y);
}
} else {
System.out.println("OPERATOR NOT VALID");
}
}
I want the results to show only one value at all times

You may add another condition to check at any point in this control structure.
For example, assuming that you are wanting to add a logarithmic function to your program, and assuming the method signature of that function contains log(double value, double base), you could add the statements...
else if (op == "log") {
log(x, y);
}
...anywhere after your initial if statement and before the else statement. You could even replace your initial if statement with checking this condition and push your current if statement down into the series of else if statements if you so desired.
Given this level of freedom, your ultimate goal in designing this program should be to manage complexity such that someone else trying to read your code will easily understand your intentions. What I mean by this is that, although you may add this condition anywhere, you should place it where it will make the most sense.
In my opinion, seeing as your control structure first checks for the multiplication and division operators, and then for the addition and subtraction operators, followed by a check for the exponential/square-root operator, I would place the check for a logarithmic operator just after your check for the exponential/square-root operator, and just before your else statement.
I'd also advise separating the exponential/square-root operation into two separate else if statements, and defining an op code for both of these operations rather than using an empty op code to target those operations. I advise this not only for the sake of clarity and readability in your code; there is another reason.
For someone to understand that they should pass in the String "" as an op code to this program, they would need to understand its inner workings. A big part of object-oriented programming is 'information hiding', or attempting to make your methods and classes understandable without needing to know how they are implemented. Assume that someone wants to use this program without reading its inner workings. If no one else is going to be using this program, assume that you want to use this program a year from now, and you don't want to have to read through the program again to understand what it's doing. You just want to pass in two values and an op code and receive the value you want.
In this scenario a more user-friendly implementation would be to give each possible inner operation a clearly defined op code. You could provide a list of op codes and a description of their functions as documentation for reference by your users, even if that just means yourself.
As a small justification, imagine a user accidentally attempting to pass the String "" into this method as the op code. The ideal response in this scenario would be to inform the user that an invalid op code has been passed in to the method, but in your current implementation the method would either perform a square-root or exponential operation, depending on the values passed in. If this behavior is unexpected by the user, they will likely be confused and will probably waste some time trying to understand why this method isn't behaving like they would expect it to behave.
Another small suggestion would be to use the String comparison function equals() to compare the passed in op code to each value you're checking. The documentation for this function can be found here, and a revised version of your program would look like this:
public void OperatorIndicator(double x, double y, String op){
if (op.equals("+")) {
multiply(x, y);
} else if (op.equals("/")) {
divide(x, y);
} else if (op.equals("+")) {
sum(x, y);
} else if (op.equals("-")) {
difference(x, y);
} else if (op.equals("")){
if (y == 0) {
squareroot(x);
} else {
exponent(x,y);
}
} else {
System.out.println("OPERATOR NOT VALID");
}
}

I don't know if you already know about it, but in your case, you can use pretty well statement like switch. It would look like:
public void OperatorIndicator(double x, double y, String op){
switch(op) {
case "*": multiply(x, y); break;
case "/": divide(x, y); break;
case "+": sum(x, y); break;
case "-": difference(x, y); break;
case "^": pow(x, y); break;
case "log": log(x, y); break;
// ...
default:
System.out.println("OPERATOR NOT VALID");
}
}

Related

How can i simplify this if sequence?

I am learning java, and i got stuck in a stupid situation.
I could just throw all my code in here, but it would only confuse you even more. So I converted my logical thinking into this:
if (a)
{
*instruction 1*
}
if (!a && b && !c)
{
*instruction 2*
}
if (!a && b && c)
{
*instruction 3*
}
else
{
*instruction 4*
}
All I want to know is if i can simplify this, so i don't use so many "if" statements...
And I'd like to know how you came to your conclusion.
Thanks in advance! (Yes, I'm dumb, help me)
EDIT:
I'm adding a truth-table with every combination of a, b and c:
If a, b and c are local variables or otherwise guaranteed not to change while you go through the if-statements, then you can write your code as:
if (a) {
// instruction 1
} else if (b) {
if (!c) {
// instruction 2
} else {
// instruction 3
}
}
if (a || !b || !c) {
// instruction 4
}
However, it is still pretty complex. Depending on the meaning of a, b and c and how you calculate them, you should probably refactor this code into multiple methods. For example, the if-statement relating to c might fit well into a single-responsibility method.
If you want to verify whether this change is correct, you can create a truth-table with all possible combinations of a, b and c being true or false. You would check which instruction would be performed in your first code, and which instruction gets performed in the new code.
You probably want to use a switch statement to make this more readable.
Something like:
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
The switch statement is a multi-way branch statement. It provides an easy way to dispatch execution to different parts of code based on the value of the expression. Basically, the expression can be byte, short, char, and int primitive data types. Beginning with JDK7, it also works with enumerated types ( Enums in java), the String class and Wrapper classes.
As far as i can see there's a Wrapper Class for Booleans.
boolean result = switch (ternaryBool) {
case TRUE -> true;
case FALSE -> false;
case FILE_NOT_FOUND -> throw new UncheckedIOException(
"This is ridiculous!",
new FileNotFoundException());
// as we'll see in "Exhaustiveness", `default` is not necessary
default -> throw new IllegalArgumentException("Seriously?! 🤬");
};
https://blog.codefx.org/java/switch-expressions/
In multiple conditions, I would use the switch statement to make it easier to read.
https://beginnersbook.com/2017/08/java-switch-case/

Better way to handle n number of if-else if in java

I was wondering if there is any better way to handle n no. of if/else-if block in Java.
I have a situation where I need to print different values based on n no. of if/else-if/conditions blocks like
if(p==1 && q==r)
System.out.println("Condition 1");
else if(r==p && q==9)
System.out.println("Condition 2");
else if(z==1 && s==r)
System.out.println("Condition 3");
else if(p==1 || x==r && y==7)
System.out.println("Condition 4");
else if(q==z && y==r || p==4)
System.out.println("Condition 5");
else if(x==z && r==5 || z==30)
System.out.println("Condition 6");
else if(s==1 || q==x)
System.out.println("Condition 7");
else if(r==14 || q==r++ || z==y)
System.out.println("Condition 8");
else if(q==18 && s==r || p==90)
System.out.println("Condition 9");
else if(y==19 || q==89)
System.out.println("Condition 10");
...
Is there any other way to handle it instead of putting multiple if/else if statements so that if later on any new condition come, it will be easy to handle it.
The real answer here: don't do that.
In good OO design, you solve this problem in very different ways; for example by using polymorphism. You actually want to avoid having many different sources of information, to then make decisions on that.
In your case; I would be thinking towards FSMs and the state pattern for example.
What I mean is: your code is showing a certain "approach" towards solving a problem. And as long as you keep that approach as is, you are only talking about finding ways to express your solution in the "least ugly" way.
Instead, you should step back and look into approaches that can be expressed in "really beautiful" ways.
Thus: there is no "simple" direct answer to your question. You have to step back and have a close look at the requirements you want to fulfill; to then design a better, "more OO" solution to that.
The minimal thing here: you could start by declaring an enum like:
public enum Condition {
A, B, C, ...
and then you would have some factory method that hides all those statements; like:
Condition currentCondition = determineCondition(p, q, r, z);
switch(currentCondition) {
case A:
Meaning: you want to at least "centralize" that knowledge somewhere to avoid code duplication. But again; that is just like putting some new color on an old, rusty car. It helps for the moment, but doesn't really improve things.
Regarding your comments: yes, the switch is only marginally "better" than if elses. But as you said: you can't make too many chances, so at least you want to have exactly one piece of code that determines state.
But in the end: I think you are approaching this on a wrong level. You are probably dealing with some kind of complicated business logic; and you want to solve that on a low level like this. But nothing you do on such a level will lead to a robust, long-term maintainable solution. Probably the real solution is to step back and look into using some kind of workflow engine.
You can make a Condition (interface or superclass) which accepts all your variables:
public interface Condition {
boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z);
void performAction();
}
For each single Condition you can override/implement a boolean method isConditionMet().
public class C1 implements Condition {
public boolean isConditionMet(int p, int q, int r, int s, int x, int y, int z) {
return p == 1 && q == r;
}
public void performAction() {
System.out.println("Condition 1");
}
}
Then you can put all conditions in a collection, and for each Condition you have you can ask:
if (condition.isConditionMet())
condition.performAction();
Now each Condition object itself is responsible for when it should act, and what it should do then. A perfect separation of concerns.
Downvote bait
When you say "if any new condition come" do you mean you are willing to modify the code if a new condition comes, or must the code adapt without being modified? If the former, I think you've done it the best way. (Though, I would add an if (false){} at the top, so all the real cases look the same, making it easy to rearrange them.) If the latter, then a table-driven approach is needed. Performance is not an issue if every case has a print statement. If you do care about performance, then put the most common cases first.
If you care even more about performance, have a tree of if-statements, rather than a ladder. So, for example, have something like this, so you're not repeatedly asking the same sub-question:
if (p == 1){
.. all the cases where p is 1
} else {
.. all the other cases
}
There may be other OO-related ways to write this, but none of them will be faster or easier to modify than this.

Recursive return error, Java

So I'm defining a recursive function that takes as an argument a value for x (like the arithmetic variable x, i.e. "x + 3 = 5") and returns the result of the arithmetic expression. The expression is taken from a Binary expression tree that looks like this:
You start at the root and keep working your way down till you hit the leaves, and once you do you come back up. The expression on the tree is then:
x * ( (x + 2) + cos(x-4) ).
My code for this function is as follows:
// Returns the value of the expression rooted at a given node
// when x has a certain value
double evaluate(double x) {
if (this.isLeaf()) {
//convert every instance of 'x' to the specified value
if (this.value.equals("x")) {
this.value = Double.toString(x);
}
//return the string-converted-to-double
return Double.parseDouble(this.value);
}
//if-else statements to work as the arithmetic operations from the tree. Checks the given node and performs the required operation
else {
if(this.value.equals("sin")) { return Math.sin(evaluate(Double.parseDouble(this.leftChild.value))); }
if(this.value.equals("cos")) { return Math.cos(evaluate(Double.parseDouble(this.leftChild.value))); }
if(this.value.equals("exp")) { return Math.pow(evaluate(Double.parseDouble(this.leftChild.value)), evaluate(Double.parseDouble(this.rightChild.value))); }
if(this.value.equals("*")) { return evaluate(Double.parseDouble(this.leftChild.value)) * evaluate(Double.parseDouble(this.rightChild.value)); }
if(this.value.equals("/")) { return evaluate(Double.parseDouble(this.leftChild.value)) / evaluate(Double.parseDouble(this.rightChild.value)); }
if(this.value.equals("+")) { return evaluate(Double.parseDouble(this.leftChild.value)) + evaluate(Double.parseDouble(this.rightChild.value)); }
if(this.value.equals("-")) { return evaluate(Double.parseDouble(this.leftChild.value)) - evaluate(Double.parseDouble(this.rightChild.value)); }
}
}
However the compiler is tossing an error telling me that my function must return a type double. Both the if and the else statements return a double- the if statement directly and the else statement through the sum of 2 doubles returned by the same function. What is the deal here? If I place a return statement outside of the if-else then the error resolves itself but to work with that would require me to keep a static or a global variable consistent through each recursion. I'd like to know what is wrong with my function as is, because it feels much more intuitive than a global variable and I think I'm missing a key concept about recursion here. Any help is appreciated- thank you!
Both the if and the else statements return a double
They actually don't. The if branch always does, but the else branch doesn't. What happens if this.value equals "Invalid", or something else which isn't in your list? Then it won't ever hit a return statement. Since it's required to always return, or throw an exception, this isn't allowed.
Even if you have your program structured in such a way that it logically always has to return a value, the compiler isn't going to be doing complex analysis on all the branches of your program to ensure that it always returns something. It just checks that each branch has a valid return.
So, for example, something like is invalid
if(x < 0) return -1;
if(x >= 0) return 1;
Because the compiler doesn't know that it always has to hit one of those two conditions (an issue which is further complicated by the fact that, depending on what x is, it might not always have to go down one of those branches).
Instead, your code should be structured like this:
if(x < 0) return -1;
else return 1;
So that every branch has a valid exit condition.

How to avoid code duplication?

Is it possible to avoid code duplication in such cases? (Java code)
void f()
{
int r;
boolean condition = true;
while(condition)
{
// some code here (1)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (2)
r = check();
if(r == 0)
break ;
else if(r == 1)
return ;
else if(r == 2)
continue ;
else if(r == 3)
condition = false;
// some code here (3)
}
// some code here (4)
}
int check()
{
// check a condition and return something
}
A possible solution may be using Exceptions, but that doesn't seem to be a good practice.
Is there any so-called good pattern of program flow control in such cases? For example, a way to call break ; from inside the check() function.
(Possibly in other programming languages)
Some good answers (especially #Garrett's just now) to a tough question but I'll add my $0.02 for posterity.
There is no easy answer here about how to refactor this block without seeing the actual code but my reaction to it is that it needs to be redesigned.
For example, a way to call break ; from inside the check() function. (Possibly in other programming languages)
If you are asking for a different break that Java does not support (without a hack) and having the duplicated check() and various different loop exit/repeat code indicates to me that this is a large and complicated method. Here are some ideas for you to think about:
Each of the some code here blocks are doing something. If you pull those out to their own methods, how does that change the loop?
Maybe break the loop down into a series of comments. Don't get deep into the code but think about it conceptually to see if a different configuration drops out.
Have you had another developer in your organization who is not involved with this code take a look at it? If you explain in detail how the code works someone they may see some patterns that you are not since you are in the weeds.
I also think that #aix's idea of a finite state machine is a good one but I've needed to use this sort of mechanism very few times in my programming journeys -- mostly during pattern recognition. I suspect that a redesign of the code with smaller code blocks pulled into methods will be enough to improve the code.
If you do want to implement the state machine here are some more details. You could have a loop that was only running a single switch statement that called methods. Each method would return the next value for the switch. This doesn't match your code completely but something like:
int state = 0;
WHILE: while(true) {
switch (state) {
case 0:
// 1st some code here
state = 1;
break;
case 1:
state = check();
break;
case 2:
return;
case 3:
break WHILE;
case 4:
// 2nd some code
state = 1;
break;
...
}
}
Hope some of this helps and best of luck.
The best way to avoid this duplication is not to let it happen in the first place by keeping your methods small and focused.
If the // some code here blocks are not independent, then you need to post all the code before someone can help you refactor it. If they are independent then there are ways to refactor it.
Code smell
First of all, I second aix's answer: rewrite your code! For this, the state design pattern might help. I would also say that using break, continue and return in such a way is just as much a code smell as the code duplication itself.
Having said that, here is a solution, just for fun
private int r;
void f()
{
distinction({void => codeBlock1()}, {void => codeBlock4()}, {void => f()},
{void => distinction( {void => codeBlock2()},{void => codeBlock4()},
{void => f()}, {void => codeBlock3()} )
});
}
void distinction( {void=>void} startingBlock, {void=>void} r0Block, {void=>void} r2Block, {void=>void} r3Block){
startingBlock.invoke();
r = check();
if(r == 0)
r0Block.invoke();
else if(r == 1)
{}
else if(r == 2)
r2Block.invoke();
else if(r == 3)
// if condition might be changed in some codeBlock, you still
// would need the variable condition and set it to false here.
r3Block.invoke();
}
This uses closures. Of course the parameters r0Block and r2Block could be ommited and instead codeBlock4() and f() hard-coded within distinction(). But then distinction() would only be usable by f(). With Java <=7, you would need to use an Interface with the method invoke() instead, with the 4 implementations codeBlock1 to codeBlock4. Of course this approach is not at all readable, but so general that it would work for any business logic within the codeBlocks and even any break/return/continue-orgy.
Not really.
The second continue is redundant (your code would continue anyway).
Try using the Switch statement. It will make your code more readable.
One nicer way to do it would be to use switch statements, something like this:
void f()
{
int r;
boolean condition = true;
while(condition)
{
outerloop:
r = check();
switch(r){
case 0: break outerloop;
case 1: return;
case 2: continue;
case 3: condition = false;
}
You might want to think about re-formulating your logic as a state machine. It might simplify things, and will probably make the logic easier to follow.

Optimizing if-else /switch-case with string options

What modification would bring to this piece of code? In the last lines, should I use more if-else structures, instead of "if-if-if"
if (action.equals("opt1"))
{
//something
}
else
{
if (action.equals("opt2"))
{
//something
}
else
{
if ((action.equals("opt3")) || (action.equals("opt4")))
{
//something
}
if (action.equals("opt5"))
{
//something
}
if (action.equals("opt6"))
{
//something
}
}
}
Later Edit: This is Java. I don't think that switch-case structure will work with Strings.
Later Edit 2:
A switch works with the byte, short,
char, and int primitive data types. It
also works with enumerated types
(discussed in Classes and Inheritance)
and a few special classes that "wrap"
certain primitive types: Character,
Byte, Short, and Integer (discussed
in Simple Data Objects ).
Even if you don't use a switch statement, yes, use else if to avoid useless comparison: if the first if is taken, you don't want all others ifs to be evaluated here since they'll always be false. Also you don't need indenting each if making the last block being so indented that you can't see it without scrolling, the following code is perfectly readable:
if (action.equals("opt1")) {
}
else if (action.equals("opt2")) {
}
else if (action.equals("opt3")) {
}
else {
}
Use a dictionary with string as key type and delegates* as value type.
- Retrieving the method from using the string will take O(1+load).
Fill the dictionary within the class's constructor.
Java does not support delegate, so as a work around you may need to define a few inner classes - one for each case and pass the instance of the inner classes instead of the methods as values.
Use a switch statement assuming your language supports switching on a string.
switch(action)
{
case "opt6":
//
break;
case "opt7":
//
...
...
...
}
There are a number of ways to do this in Java, but here's a neat one.
enum Option {
opt1, opt2, opt3, opt4, opt5, opt6
}
...
switch (Option.valueOf(s)) {
case opt1:
// do opt1
break;
case opt2:
// do opt2
break;
case opt3: case opt4:
// do opt3 or opt4
break;
...
}
Note that valueOf(String) will throw an IllegalArgumentException if the argument
is not the name of one of the members of the enumeration. Under the hood, the implementation of valueOf uses a static hashmap to map its String argument to an enumeration value.
You can use a switch.
switch (action)
{
case "opt3":
case "opt4":
doSomething;
break;
case "opt5":
doSomething;
break;
default:
doSomeWork;
break;
}
It could help if you specified the language... As it looks like C++, you could use switch.
switch (action) {
case "opt1":
// something
break;
case "opt2":
// something
break;
...
}
And in case you want to use if statements, I think you could improve readability and performance a bit if you used "else if" without the curly braces, as in:
if (action.equals("opt1")) {
//something
} else if (action.equals("opt2")) {
//something
} else if ((action.equals("opt3")) || (action.equals("opt4"))) {
//something
} else if (action.equals("opt5")) {
//something
} else if (action.equals("opt6")) {
//something
}
I think some compilers can optimize else if better than a else { if. Anyways, I hope I could help!
I would just clean it up as a series of if/else statements:
if(action.equals("opt1"))
{
// something
}
else if (action.equals("opt2"))
{
// something
}
else if (action.equals("opt3"))
{
// something
}
etc...
It depends on your language, but it looks C-like, so you could try a switch statement:
switch(action)
{
case "opt1":
// something
break;
case "opt2":
// something
break;
case "opt3":
case "opt4":
// something
break;
case "opt5":
// something
break;
case "opt6":
// something
break;
}
However, sometimes switch statements don't provide enough clarity or flexibility (and as Victor noted below, will not work for strings in some languages). Most programming languages will have a way of saying "else if", so rather than writing
if (condition1)
{
...
}
else
{
if (condition2)
{
...
}
else
{
if (condition3)
{
...
}
else
{
// This can get very indented very fast
}
}
}
...which has a heap of indents, you can write something like this:
if (condition1)
{
...
}
else if (condition2)
{
...
}
else if (condition3)
{
...
}
else
{
...
}
In C/C++ and I believe C#, it's else if. In Python, it's elif.
The answers advising the use of a switch statement are the way to go. A switch statement is much easier to read than the mess of if and if...else statements you have now.
Simple comparisons are fast, and the //something code won't executed for all but one case, so you can skip "optimizing" and go for "maintainability."
Of course, that's assuming that the action.equals() method does something trivial and inexpensive like a ==. If action.equals() is expensive, you've got other problems.
Procedural switching like this very often is better handled by polymorphism - rather than having an action represented by a string, represent an action by an object who has a 'something' method you can specialise. If you find you do need to map a string to the option, use a Map<String,Option>.
If you want to stick to procedural code, and the options in your real code really are all "optX":
if ( action.startsWith("opt") && action.length() == 4 ) {
switch ( action.charAt(3) ) {
case '1': something; break;
case '2': something; break;
case '3': something; break;
...
}
}
which would be OK in something like a parser ( where breaking strings up is part of the problem domain ), and should be fast, but isn't cohesive ( the connection between the object action and the behaviour is based on the parts of its representation, rather than anything intrinsic in of the object ).
In fact this depends on branch analysis. If 99% of your decisions are "opt1" this code is already pretty good. If 99% of your decisions are "opt6" this code is ugly bad.
If you got often "opt6" and seldom "opt1" put "opt6" in the first comparison and order the following comparisons according to the frequency of the strings in your execution data stream.
If you have a lot of options and all have equal frequency you can sort the options and split them into a form of a binary tree like this:
if (action < "opt20")
{
if( action < "opt10" )
{
if( action == "opt4" ) {...}
else if( action == "opt2" ) {...}
else if( action == "opt1" ) {...}
else if( action == "opt8" ) {...}
}
}
else
{
if( action < "opt30 )
{
}
else
{
if( action == "opt38" ) {...}
else if( action == "opt32" ) {...}
}
}
In this sample the the range splits reduces the needed comparisons for "opt38" and "opt4" to 3. Doing this consequent you get log2(n) +1 comparisons in every branch. this is best for equal frequencies of the options.
Don't do the binary spit to the end, at the end use 4-10 "normal" else if constructs that are ordered by the frequency of the options. The last two or three levels in a binary tree don't take much advance.
Summary
At least there are two optimizations for this kind of comparisons.
Binary Decision Trees
Ordering due to the frequency of the options
The binary decision tree is used for large switch-case constructs by the compiler. But the compiler don't know anything about frequencies of an option. So the ordering according to the frequencies can be a performance benefit to the use of switch-case if one or two options are much more frequent than others. In this case this is a workaround:
if (action == "opt5") // Processing a frequent (99%) option first
{
}
else // Processing less frequent options (>1%) second
{
switch( action )
{
case "opt1": ...
case "opt2": ...
}
}
Warning
Don't optimize your code until you have done profiling and it is really necessary. It is best to use switch-case or else-if straight forward and your code keeps clean and readable. If you have optimized your code, place some good comments in the code so everybody can understand this ugly peace of code. One year later you won't know the profiling data and some comments will be really helpful.
If you find the native java switch construct is too much limiting give a glance to the lambdaj Switcher that allows to declaratively switch on any object by matching them with some hamcrest matchers.
Note that using strings in the cases of a switch statement is one of the new features that will be added in the next version of Java.
See Project Coin: Proposal for Strings in switch

Categories

Resources