Method always returns zero - java

I'm pretty new to java and I'm trying to create a program that quizzes users on the difference between 2 random frequencies. Everything works except that when I try to get the difference of 2 frequencies the answer is always 0. How do I get it to display the actual difference? Here is the class I wrote to create the tones ans compute the difference:
public class Quiz{
private PitchPlay one = new PitchPlay();
private PitchPlay two = new PitchPlay();
private int frequencyOne;
private int frequencyTwo;
private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
public int run(){
frequencyOne = new Integer((int)(Math.random() * 5000 + 50));
frequencyTwo = new Integer((int)(Math.random() * 5000 + 50));
return this.dif;
}
public int freqDif(){
return this.dif;
}
public void playQuiz(){
one.play(one.note(frequencyOne, 2, 15));//note(frequency, duration, volume)
two.play(two.note(frequencyTwo, 2, 15));
}
}
And here is the class where the quiz class is used:
public class Action implements ActionListener{
Quiz one = new Quiz();
public void actionPerformed (ActionEvent e){
if(e.getSource() == playSoundButton)
{
if(answerResponse.getText().compareTo("Correct!") == 0 || answerResponse.getText().compareTo("Play and Listen...") == 0)
{
one.run();
one.playQuiz();
}
else
{
one.playQuiz();
}
}
if(e.getSource() == submitButton)
{
String responseText = new String(responseField.getText());
if(responseText !=null && !"".equals(responseText)){
try{
Integer responseNumber = Integer.parseInt(responseText);
if(responseNumber == one.freqDif())
{
answerResponse.setText("Correct!");
answerResponse.setVisible(true);
}
else
{
answerResponse.setText("Wrong Answer. The difference is " + one.freqDif() + " hertz.");
answerResponse.setVisible(true);
}
}catch(NumberFormatException f){
f.printStackTrace(System.out);
}
}
}
}
}

private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
This is calculated when the variable is created, not when you use the variable. You need to do the calculation after assigning the variables.

There are several issues with your code:
As others have mentioned, the line
private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
creates a variable and assigns a value calculated from two other variables. The values of the other variables at the time of creation are used. You need to recalculate every time the values of those two variables changes. This does not happen automatically for you.
new Integer(...) creates an Integer object. When you subsequently assign this object to an int variable, the value is taken out of the object. This adds some unnecessary memory and run-time over head to your code. Instead, you should assign directly to your variables. For example,
frequencyOne = (int)(Math.random() * 5000 + 50);

Related

When I run my methods it keeps repeating itself and doesn't move on java

Like the caption said the method "scanInput1" runs two times in a row when it should only run once. Then the method "arrayskapare" runs as intended but after that. instead of running the method "medelvarde" is jumps back and runs "scanInput1" again and again and again
import java.util.*;
class Heltalshanterare{
private static String scanInput1(){
System.out.print("Skriv in antal heltal: ");
Scanner scr = new Scanner(System.in);
String antalHeltal = scr.next();
try {
Integer.parseInt(antalHeltal);
}
catch (NumberFormatException e) {
System.out.println("Ogilitigt värde");
scanInput1();
}
return antalHeltal;
}
private static List<Integer> arrayskapare() {
int antalangivnatal = Integer.parseInt(scanInput1());
int noll = 1;
int heltal = 0;
String tal1 = "";
Scanner tal = new Scanner(System.in);
List<Integer> list = new ArrayList<>();
while (noll <= antalangivnatal) {
noll++;
heltal++;
System.out.print("ange heltal " + heltal + ": ");
tal1 = tal.next();
try {
int num = Integer.parseInt(tal1);
list.add(num);
} catch (NumberFormatException e) {
System.out.println("Ogiltigt värde");
noll--;
heltal--;
}
}
return list;
}
public static int medelvarde(){
int antalsiffror = arrayskapare().size();
int sum = 0;
for (int i : arrayskapare()){sum += i;}
int medelvärde = sum / antalsiffror;
System.out.println("medelvärdet av dina tal är " + medelvärde);
return medelvarde();
}
public static void main(String [] args){
scanInput1();
arrayskapare();
medelvarde();
}
}
Im sorry that the code is so long but I have been struggling with this for too long and I really need some help.
Your main method is calling each method just once, which is what you need. But it's not actually holding onto any of the values being returned. So the number of heltal (integers in English) is captured from the user but then never actually stored anywhere. And later an array of numbers is captured but not stored anywhere.
Your second, bigger problem is that your methods are then calling the earlier methods all over again. So instead of asking the user to type in the data just once, you're forcing them to answer the exact same questions multiple times.
A much tidier approach is to alter your methods so that they take the required data as a parameter. Which means your arrayskapare (array producer) method should take the antalHeltal (number of integers) value as a parameter, and then it won't need to call the scanInput1 method again. Same thing can be done for your medelvarde (mean value) method: have it take the array as a method parameter, so that it won't need to call arrayskapare.
With those changes your main method can simply look like this:
public static void main(String [] args){
int antalHeltal = scanInput1();
List<Integer> heltalArray = arrayskapare(antalHeltal);
int medelvardet = medelvarde(heltalArray);
System.out.println("Medelvärdet är " + medelvardet);
}
Now each method just gets called once and the data captured from the user gets stored into variables and passed along the river of methods until the final result is reached.

I'm trying to add a value to an int in one class and then use it in another, Java

So as the title says im struggling to add a value to an integer and then pass it to another class that uses it, then this class will pass it to the next and then that one will pass it over to the main class. Its an integer that changes the stat template of the enemies in my small game im writing.
I have tried to make constructors in two of my classes as I thought that was the problem, Ive tried to see if they work by passing some messages in them.
The problem seems to be that when I save something in the "private int l" It dosnt actually change the value of that int and I cant figure out why that is.
Here is my code, its probably not very pretty so if you have any suggestions to structure changes that I might wanna do please feel free too let me know!
Thanks in advance!
import java.util.Scanner;
public class Stor {
public static void main(String[] args) {
Scanner user_Input = new Scanner(System.in);
Menu user = new Menu();
EnemyValue monster = new EnemyValue();
user.namn();
user.AnvNamn = user_Input.next();
user.introMeny();
user.difficulty();
System.out.println(“Your enemy has " + monster.HP + " HP and " +
monster.DMG + " Damage" );
user_Input.close();
}
}
class Menu {
Scanner user_Input = new Scanner(System.in);
String AnvNamn;
String difficultySvar;
String nivåSvar;
int svar;
private int i; /
private int l;
public int getL() {
return l;
}
boolean difficultyLoop = true;
boolean felLoop = true;
void introMeny() {
System.out.println(“Welcome " + AnvNamn + "!");
}
void namn() {
System.out.print(“Pick a name: “);
}
void difficulty() {
do {
System.out.println("\nWhat level do you want ?\n1 = Easy.\n2 =
Medium.\n3 = Hard.”);
svar = user_Input.nextInt();
if (svar == 1) {
System.out.println(“Your not very brave are you ? Are you sure
this is how you wanna play ?”);
difficultySvar = user_Input.next();
if (difficultySvar.equalsIgnoreCase(“Yes”)) {
difficultyLoop = false;
l = 1;
} // If ja 1
else if (difficultySvar.equalsIgnoreCase(“Nej”)) {
System.out.println(“Ahh good! I figuerd you would change
your mind.”);
}
else
System.out.println(“I don’t understand….”);
} // if 1
else if (svar == 2) {
System.out.println(“Not to hard or to easy, a good choice! But
maybe you want to go for something harder ? Or maybe easier ?");
difficultySvar = user_Input.next();
if (difficultySvar.equalsIgnoreCase(“Yes”)) {
difficultyLoop = false;
l = 2;
} // if ja 2
else if (difficultySvar.equalsIgnoreCase(“No”)) {
System.out.println(“I sure hope you don’t pick the easy
way…..”);
}
else
System.out.println("I don’t understand….");
} // Else if 2
else if (svar == 3) {
System.out.println(“Damn! We have a big player here! Are you
sure you can handle this ?");
difficultySvar = user_Input.next();
if (difficultySvar.equalsIgnoreCase(“Yes”)) {
difficultyLoop = false;
l = 3;
} // If ja 3
else if (difficultySvar.equalsIgnoreCase(“No”)) {
System.out.println(“Wuss.”);
}
else
System.out.println(“I don’t understand….”);
} // Else if 3
else {
if (i == 0) {
System.out.println(“Ha you thought you could fool the system?!
The system fools you!”);
System.out.println(“Nah but seriously, you can only choose
between 1-3…..“);
i++;
} // if i 0
else if (i == 1) {
System.out.println(“Alright I get that its hard but
COMEON!”);
i++;
} // if i 1
else if (i == 2) {
System.out.println(“OKEY YOU GET ONE LAST CHANCE!!”);
i++;
} // if i 2
else if (i == 3) {
System.out.println(“Alright thats it…. GET OUT!”);
System.exit(0);
} // if i 3
} // Else
} // do while loop
while(difficultyLoop == true);
} //Difficulty metod.
} // Menu class.
class Nivå {
//Menu level = new Menu();
//int levelChoice = level.getL();
int levelChoice;
private int enemyLife;
public int getenemyLife() {
return enemyLife;
}
private int enemyDMG;
public int getenemyDMG() {
return enemyDMG;
}
Nivå(){
Menu level = new Menu();
levelChoice = level.getL();
System.out.println("testNivå");
}
void fiendeLiv() {
if (levelChoice == 1)
enemyLife = 100;
else if (levelChoice == 2)
enemyLife = 150;
else if (levelChoice == 3)
enemyLife = 200;
} // fiendeliv method
void fiendeDMG() {
if (levelChoice == 1)
enemyDMG = 5;
else if (levelChoice == 2)
enemyDMG = 10;
else if (levelChoice == 3)
enemyDMG = 15;
} // fiendeDMG method
} // Nivå class
class EnemyValue {
public int HP;
public int DMG;
int maxLife;
int maxDMG;
EnemyValue(){
Nivå stats = new Nivå();
maxLife = stats.getenemyLife();
maxDMG = stats.getenemyDMG();
System.out.println("TestEnemyValue");
}
void rank1() {
HP = maxLife;
DMG = maxDMG;
} // rank1 easy method
} // EnemyValue class
You say that when you save something in l (poor choice of a variable name, by the way) it does not save the value. How do you know that? Where in the code do you check whether the value is saved?
In the constructor for class Nivå you create a new Menu and then call getL() on that menu before you have ever set the value of that variable.
Everything runs at the start of your public static void main(String[] args) method, and nothing will run if its instructions are not in there. For example, you are not actually creating any Niva objects in the main method, so the Niva constructor is never called. That is one issue. The other is your constructors are creating new instances of objects and then getting their values; this gives you empty values from a brand new object:
Nivå(){
Menu level = new Menu(); // Don't do this. This is an empty menu
levelChoice = level.getL(); // Getting the blank L value from the empty menu
System.out.println("testNivå");
}
Instead, you need to define constructors with parameters to pass the values into the class like this:
Nivå(int level){ // add an int parameter
levelChoice = level; // Direct assignment
fiendeDMG(); // Call this in the constructor to set up your last value
System.out.println("testNivå");
}
Then, when you call the constructor (which you must if you want it to exist), include the parameter. Inside the Stor class:
public static void main(String[] args) {
Scanner user_Input = new Scanner(System.in);
Menu user = new Menu();
user.namn();
user.AnvNamn = user_Input.next();
user.introMeny();
user.difficulty(); // Run this before creating the other classes; you need the l value
Nivå niva = new Nivå(user.getL()); // Creates new Niva while also assigning l to the levelChoice and then getting DMG
EnemyValue monster = new EnemyValue(/*add some parameters for life and dmg*/);
}
There is still more that needs to be done, like modifying the constructor of the EnemyLevel. Just remember that methods are never called unless they connect to something running from main and use parameters in functions and constructors to pass on data to other objects. Hope this helps.

Weird behavior with Java objects: supposedly the same process, different result

I am experiencing a weird behavior with Java objects. I have this ComponentPlane.class with two different versions. Difference is marked by ******.
First WORKING Version
package app.pathsom.som.output;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import app.pathsom.som.map.Lattice;
import app.pathsom.som.map.Node;
public class ComponentPlane extends JPanel{
private Lattice lattice;
private int componentNumber;
private double minValue;
private double maxValue;
private double origMinValue;
private double origMaxValue;
public ComponentPlane(Lattice lattice, int componentNumber){
this.lattice = new Lattice();
this.componentNumber = componentNumber;
initLattice(lattice);
initComponentPlane();
}
private void initLattice(Lattice lattice){
this.lattice.setLatticeHeight(lattice.getLatticeHeight());
this.lattice.setLatticeWidth(lattice.getLatticeWidth());
this.lattice.setNumberOfNodeElements(lattice.getNumberOfNodeElements());
this.lattice.initializeValues();
this.lattice.setNodeHeight(lattice.getNodeHeight());
this.lattice.setNodeWidth(lattice.getNodeWidth());
this.lattice.setTotalNumberOfNodes(lattice.getTotalNumberOfNodes());
for(int i = 0; i < lattice.getTotalNumberOfNodes(); i++){
******this.lattice.getLatticeNode()[i] = new Node(lattice.getLatticeNode()[i]);******
}
}
}
The only difference of the second NON-WORKING version is with this FUNCTION REPLACING the FUNCTION above
private void initLattice(Lattice lattice){
//same code here
for(int i = 0; i < lattice.getTotalNumberOfNodes(); i++){
******this.lattice.getLatticeNode()[i] = lattice.getLatticeNode()[i];******
}
}
I have also tried doing a third non-working version which is...
private void initLattice(Lattice lattice){
//same code here
******this.lattice.setLatticeNode(lattice.getLatticeNode());******
}
A constructor in the Node.class (WHICH is USED in the first WORKING version is this one...
public Node (Node node){
this.xPos = node.xPos;
this.yPos = node.yPos;
this.numOfElements = node.numOfElements;
this.cluster = -1;
this.nodeIndex = node.getNodeIndex();
for(int i = 0; i < this.numOfElements; i++){
this.addElement(node.getDoubleElementAt(i));
}
}
Lattice.class
public class Lattice {
private int latticeWidth;
private int latticeHeight;
private int numOfNodeElements;
private int nodeWidth;
private int nodeHeight;
private int totalNumOfNodes;
private Node[] latticeNodes;
private final int MAP_RADIUS = 225;
public Lattice(int latticeWidth, int latticeHeight, int numOfNodeElements){
this.latticeWidth = latticeWidth;
this.latticeHeight = latticeHeight;
this.numOfNodeElements = numOfNodeElements;
initializeLattice();
}
public Lattice(){
this(10, 10, 3);
}
public void initializeValues(){
totalNumOfNodes = this.latticeHeight * this.latticeWidth;
latticeNodes = new Node[totalNumOfNodes]; //specify the array of nodes
nodeWidth = (int) Math.floor(450/this.latticeWidth);
nodeHeight = (int) Math.floor(450/this.latticeHeight);
}
protected void initializeLattice(){
totalNumOfNodes = this.latticeHeight * this.latticeWidth;
latticeNodes = new Node[totalNumOfNodes];
nodeWidth = (int) Math.floor(450/this.latticeWidth);
nodeHeight = (int) Math.floor(450/this.latticeHeight);
//initialize colors
for(int i = 0; i <totalNumOfNodes; i++){
latticeNodes[i] = new Node(((i % this.latticeWidth) * nodeWidth) + nodeWidth / 2,
((i / this.latticeWidth) * nodeHeight ) + nodeHeight/2, numOfNodeElements, i);
latticeNodes[i].setNodeColor(new Color((int)(latticeNodes[i].getDoubleElementAt(0)
* 255), (int)(latticeNodes[i].getDoubleElementAt(1) * 255), (int) (latticeNodes[i].getDoubleElementAt(2) * 255)));
}
}
public int getLatticeHeight(){
return latticeHeight;
}
public void setLatticeHeight(int latticeHeight){
this.latticeHeight = latticeHeight;
}
public Node[] getLatticeNode(){
return latticeNodes;
}
public void setLatticeNode(Node[] latticeNodes){
this.latticeNodes = latticeNodes;
}
public int getLatticeWidth(){
return latticeWidth;
}
public void setLatticeWidth(int latticeWidth){
this.latticeWidth = latticeWidth;
}
public int getNodeHeight(){
return nodeHeight;
}
public int getNodeWidth(){
return nodeWidth;
}
public void setNodeHeight(int nodeHeight){
this.nodeHeight = nodeHeight;
}
public void setNodeWidth(int nodeWidth){
this.nodeWidth = nodeWidth;
}
public int getNumberOfNodeElements(){
return numOfNodeElements;
}
public void setNumberOfNodeElements(int numOfNodeElements){
this.numOfNodeElements = numOfNodeElements;
}
public int getTotalNumberOfNodes(){
return totalNumOfNodes;
}
public void setTotalNumberOfNodes(int totalNumberOfNodes){
this.totalNumOfNodes = totalNumberOfNodes;
}
}
A certain Visualization.class initiates all these actions and stores the ComponentPlane arrays. Here is the function
public void initComponentPlanes(){
componentPlanes = new ComponentPlane[somtrainer.getLattice().getNumberOfNodeElements()];
int size = somtrainer.getLattice().getNumberOfNodeElements();
for(int i = 0; i < size; i++){
System.out.println(i + ": " + inputData.getVariableLabels()[i] + " size : " + size);
componentPlanes[i] = new ComponentPlane(somtrainer.getLattice(), i);
componentPlanes[i].setBounds((240 - 225)/2, (280-240)/2, 225, 240);
componentPlanes[i].setOrigMaxMin(maxMin[i][0], maxMin[i][1]);
}
}
My problems are
The First one works fine. It creates HEATMAPS or COMPONENTPLANES for each component number (meaning they differ from each other) but I cannot use it as the line with ****** which references to the ("this.addElement....") in the Node.class constructor gives me OUTOFMEMORY error so it LAGS and FREEZES whenever I have many COMPONENTPLANES to do. (I am actually doing an ARRAY of COMPONENTPlane objects) so I decided to try the second and third option. I have already increased my heap size SO this is OUT of the question
If I use the second and third one, I end up with no LAGS even with large amount of ComponentPlanes (probably less memory taking up because of creating new Node objects or idk) but these creates wrong heatmaps. All heatmaps are the same. And the thing is, all heatmaps are like the last element of the ComponentPlanes array (e.g. if I have ten ComponentPlane objects, all heatmaps look exactly like the tenth Component Object)
All of the heatmaps are like this - the same as the last heatmap in the array:
Is there a way to make the second and third one work?
The obvious difference is that in the first one you're creating new nodes, and in the others you're reusing the old ones. The line
this.lattice.getLatticeNode()[i] = lattice.getLatticeNode()[i];
is setting one object equal to another. If, later, a property of lattice.getLatticeNode()[i] changes, that will also effect this.lattice.getLatticeNode()[i]. And that can cause hard-to-find bugs. In contrast, the line
this.lattice.getLatticeNode()[i] = new Node(lattice.getLatticeNode()[i]);
is creating a new object, distinct from the old one. But, of course, this means that you're using more memory, because now you have two objects instead of one.
There are little things you can do to reduce the amount of memory used. private final int MAP_RADIUS = 225; could be made static, so a new copy of the constant isn't created for each node.

how to create threads to avoid IllegalThreadStateException

It's a multithreading exercise in which i use a Monitor to synchronize threads. I don't have problem with monitor or syncronization, there is no deadlock. I want to create some threads in the main. Code below generates threads, adds them to an ArrayList and starts them. Generates different threads with a switch-case. Since every thread should be added to ArrayList and started, i put these two lines at the end of switch-case, to not write same code in every case-state. But in this way it launches an IllegalThreadStateException.
To make my code work, i can apply different approaches, but i have some doubts for all of them. Which one would be the most appropriate way to do it?
Creating a function which will create a new myThread instance, add it to the ArrayList and start it. But since i have to call it from main, or it should be static(as i know, creating a static function without a good reason is not a good practice) or i should call it like new myClass().someMethod() but since i have to create many new threads, it would create many instances of myClass, not seem good.
public class myClass {
public static void main(String[] args) {
int scount=10, tcount=5, pcount=5;
final int SIZE = 20;
ArrayList<User> users = new ArrayList<User>();
myMonitor monitor = new myMonitor(SIZE);
User u = null;
int s = 0, t = 0, p = 0; //counters
//GENERATED CASUALLY DIFFERENT TYPE OF THREADS
while(s < scount || t < tcount || p < pcount){
int type = (int)(Math.random() * 3);
switch(type){
case 0:
if(p < pcount){
u = new User(monitor, p, "USER_TYPE_1");
p++;
}
break;
case 1:
if(t < tcount){
u = new User(monitor, p, "USER_TYPE_2");
t++;
}
break;
case 2:
if(s < scount){
u = new User(monitor, p, "USER_TYPE_2");
s++;
}
break;
}
users.add(u);
u.start();
}
}
}
public class User extends Thread{
myMonitor monitor;
final private int number;
final private String type;
final private int k;
final private int MIN = 1;
final private int MAX = 5;
public User(myMonitor monitor, int number, String type) {
this.monitor = monitor;
this.number = number;
this.type = type;
this.k = (int)(Math.random() * ((MAX - MIN) + 1)) + MIN;
}
public int getNumber() {
return number;
}
public String getType() {
return type;
}
#Override
public void run(){
for(int i=0; i<k; i++){
switch(this.type){
case "TYPE1":
monitor.startType1();
break;
case "TYPE2":
monitor.startType2(i);
break;
case "TYPE3":
monitor.startType3();
break;
}
try{
Long duration = (long) Math.ceil(Math.random() * 1000);
Thread.sleep(duration);
System.out.printf("%s-%d used system for the %d.time. Took %d ms\n",
this.type, this.number, i+1, duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch(this.type){
case "TYPE1":
monitor.endType1();
break;
case "TYPE2":
monitor.endType2(i);
break;
case "TYPE3":
monitor.endType3();
break;
}
try{
Long duration = (long) Math.ceil(Math.random() * 1000);
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf("%s-%d finished\n", this.type, this.number);
}
}
Lets carry out a thought experiment, Math.random * 3 always returns 0 - this is possible because it's obviously random (just unlikely).
Iteration 1
int s == t == p == 0
We enter the first case, as type == 0. We generate a new "P" Thread and add it to the List and start() it.
p++
Iteration 2
int s == t == 0; p == 1
We enter the first case, as type == 0. We generate a new "P" Thread and add it to the List and start() it.
p++
...
Iteration 5
int s == t == 0; p == 4
We enter the first case, as type == 0. We generate a new "P" Thread and add it to the List and start() it.
p++
Iteration 6
int s == t == 0; p == 5
We enter the first case, as type == 0. We do nothing as p >= pcount. Our thrd still points to the Thread we created in Iteration 5.
We add the same Thread to the List and start() it.
IllegalThreadStateException
Now, obviously Math.random * 3 will return different values but it will return duplicates (and your code is designed around that) - so you will get this situation.
How to avoid it? Well, you do not actually want to generate random numbers:
final List<Integer> desiredValues = new ArrayList<>(Arrays.asList(0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2));
Collections.shuffle(desiredValues)
for(final Integer value : desiredValues) {
//case switch
}
You're calling thrd.start(); even if a new thread wasn't created. Since you've declared the variable outside of the loop, it'll still refer to the previously started thread. Calling start() twice on a thread will result in an exception.
Move myThread thrd = null; inside the while loop, and only call start(); if it isn't null.

Generate Data Points for Graph from an equation

I don't want to solve an equation and my question is not about Graphs and Trees Data Structures. I am trying to generate Data Points for graph from an equation given by user. I want efficient algorithm, easy to use and easy to maintain data structures. I have two solutions in mind
1: This is trivial and I have seen in many Applications.
String expr = "2*x+3*x";
Evaluator evaluator = new Evaluator();//I have this class
for (int i = start; i < end; i += step)
{
evaluator.setConstant("x", i);
double ans = evaluator.evaluate(expr);
}
This is very slow because each time every step is repeated like tokenzing, verifying, conversion to RPN, preparing stacks and queues and at last result calculation. The possible solution to this problem is somehow caching all stacks and queues but after that a comparison would be required between current expression and previous expression to use last stored state.
2: Currently I am developing second solution. The purpose of this is efficiency and would be used in Symbolic calculation in future.
So far my implementation
Variable.java
import java.text.DecimalFormat;
public class Variable
{
private final double pow;
private final double coefficient;
private final String symbol;
public Variable(String symbol)
{
this.symbol = symbol;
this.pow = 1.0;
this.coefficient = 1.0;
}
public Variable(String symbol, double coefficient, double pow)throws IllegalArgumentException
{
if (coefficient == 0.0)throw new IllegalArgumentException("trying to create variable with coefficient 0");
if (pow == 0.0)throw new IllegalArgumentException("trying to create variable with exponent 0");
this.symbol = symbol;
this.pow = pow;
this.coefficient = coefficient;
}
public final String getSymbol()
{
return this.symbol;
}
public final double getPow()
{
return this.pow;
}
public final double getCoefficient()
{
return this.coefficient;
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
DecimalFormat decimalFormat = new DecimalFormat("#.############");
if (coefficient != 1.0)builder.append(decimalFormat.format(this.coefficient));
builder.append(this.symbol);
if (this.pow != 1.0)builder.append("^").append(decimalFormat.format(this.pow));
return builder.toString();
}
/*
* Stub Method
* Generate some unique hash code
* such that chances of key collision
* become less and easy to identify
* variables with same power and same
* symbol*/
#Override
public int hashCode()
{
return 0;
}
}
Equation.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
public class Equation
{
private final ArrayList<Boolean> operations;
private final HashMap<String, Variable> variableHashMap;
private int typesOfVariables;
public Equation(Variable variable)
{
this.variableHashMap = new HashMap<>();
this.operations = new ArrayList<>();
this.typesOfVariables = 1;
this.variableHashMap.put(variable.getSymbol(), variable);
}
/*Stub Method*/
public void addVariable(Variable variable, boolean multiply)
{
/*
* Currently not covering many cases
* 1: Add two variables which have same name
* and same pow.
* 2: variable which are wrapped inside functions e.g sin(x)
* and many other.*/
if (multiply && variableHashMap.containsKey(variable.getSymbol()))
{
Variable var = variableHashMap.get(variable.getSymbol());
Variable newVar = new Variable(var.getSymbol(), var.getCoefficient() * variable.getCoefficient(), var.getPow() + variable.getPow());
/*
* Collision chances for variables with same name but
* with different powers*/
this.variableHashMap.replace(var.getSymbol(), newVar);
}
else
{
++this.typesOfVariables;
this.variableHashMap.put(variable.getSymbol(), variable);
}
this.operations.add(multiply);
}
/*Stub Method
*Value for every variable at any point will be different*/
public double solveFor(double x)
{
if (typesOfVariables > 1)throw new IllegalArgumentException("provide values for all variables");
Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator();
Variable var;
double ans = 0.0;
if (entryIterator.hasNext())
{
var = entryIterator.next().getValue();
ans = var.getCoefficient() * Math.pow(x, var.getPow());
}
for (int i = 0; entryIterator.hasNext(); i++)
{
var = entryIterator.next().getValue();
if (this.operations.get(i))ans *= var.getCoefficient() * Math.pow(x, var.getPow());
else ans += var.getCoefficient() * Math.pow(x, var.getPow());
}
return ans;
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator();
if (entryIterator.hasNext())builder.append(entryIterator.next().getValue().toString());
Variable var;
for (int i = 0; entryIterator.hasNext(); i++)
{
var = entryIterator.next().getValue();
if (this.operations.get(i))builder.append("*").append(var.toString());
else builder.append(var.toString());
}
return builder.toString();
}
}
Main.java
class Main
{
public static void main(String[] args)
{
try
{
long t1 = System.nanoTime();
Variable variable = new Variable("x");
Variable variable1 = new Variable("x", -2.0, 1.0);
Variable variable2 = new Variable("x", 3.0, 4.0);
Equation equation = new Equation(variable);
equation.addVariable(variable1, true);//2x+x
equation.addVariable(variable2, true);
for (int i = 0; i < 1000000; i++)equation.solveFor(i);//Calculate Million Data Points
long t2 = System.nanoTime();
System.out.println((t2-t1)/1000/1000);
System.out.println(equation.toString());
}
catch (Exception e)
{
System.out.println("Error: " + e.getMessage());
}
}
}
Am I going in right direction?
Is there any commonly used Algorithm for this problem?
My main goal is efficiency, code cleanness and code maintainability.
Note: I am not native English speaker so please ignore any grammatical mistake.
Thanks.
I do not see any problem with your first code. Yes may be at every step your code "repeat like tokenzing, verifying, conversion to RPN, preparing stacks and queues and at last result calculation", but in the end all of this is just linear number of steps. So I fail to see how it can make it really slow.
One of the biggest screens I have seen was 2560x1440 pixels, which means that most of the time you would need less than 2500 points to draw your graph there.
If you point is code cleanness and code maintainability, then most probably a code consisting of 5 lines is better than the code consisting of 200.

Categories

Resources