eval function in C resulting in negative - java

I am using java 11, Eclipse IDE.
I am designing a program that needs some calculations, I am writing that program in java, so I was trying to find something similar to a function called "eval()", which evaluates an equation. So, I implemented that function in C and turned it into a ".dll" file and used it inside java.
My main problem is when I pass the equation into the eval function, and it returns a double which is negative and very huge, like : I passed it "1.0+0.5^2", and it resulted "-9.255963134931783E61", it is impossible to get to a result like that!
NOTE : it has always returned the right result, but at the last piece of execution, it has returned the above! Why? How? I am using the same eval function.
I will only show you the important parts and leave the rest, which is not important :
All codes :
eval.c :
int evaluate(char* line, double* val);
static int do_op(void);
static int do_paren(void);
static void push_op(char op);
static void push_arg(double arg);
static STATUS pop_arg(double* arg);
static STATUS pop_op(int* op);
static char* getexp(char* str);
static char* getop(char* str);
static char* getop(char* str);
JNIEXPORT jdouble JNICALL Java_application_Main_eval
(JNIEnv* env, jobject object, jstring str) {
const char* strs = env->GetStringUTFChars(str, false);
char* equation = const_cast<char*>(strs);
double result;
evaluate(equation, &result);
printf("the result is : %f", result);
jdouble* returnResult = new jdouble(result);
return *returnResult;
}
The native eval method in java :
static {
System.load(System.getProperty("user.dir")+"\\eval.dll");
}
public native double eval(String equation);
the java method that resulted something odd at the end :
String evaluateEquation(String e) {
// we will truncate the brackets into pieces and eval every piece,
// and then return it without brackets by replacing it inside the equation!
StringBuilder equation = new StringBuilder(e);
int count = countBrackets(equation);
int[] pos;
String part;
String result;
// TODO : fix here :
BigDecimal tempResult = new BigDecimal(0);
while (count!=0) { // every one loop, it will truncate, evaluate, replace the new value!
pos = lastBrackets(equation.toString());
part = equation.substring(pos[0], pos[1]+1);
System.out.println("evaluating this part : "+part);
tempResult = new BigDecimal(new Main().eval(part));
System.out.println(tempResult.toString());
result = truncateDecimals(tempResult);
equation.replace(pos[0], pos[1]+1, result);
System.out.println(equation.toString());
count--;
}
System.out.println(equation.substring(0, equation.length()));
part = equation.substring(0, equation.length()-1);
finalResult = new BigDecimal(new Main().eval(part));
System.out.println("FinalResult is : "+truncateDecimals(finalResult));
return truncateDecimals(finalResult);
}
If you have read the "eval.c" program, you will notice that it takes a "char*" and a "double&". I have taken care of these conversions and I think they have a relation with this bug. The method always returns the right result, except at one place, which is at the end of the "evaluateEquation" method.
Based on my knowledge, any number stored inside the computer memory gets to negative ONLY when we change it to a negative OR it extends on its maximum number to store. if the number breaks its limit, it will turn into a negative.
However, I noticed something, the number that is negative is being repeated again and again every time I call the eval function in the end of the "evaluateEquation" function I get the same result, which is : "-9.255963134931783E61".
If you have any assumptions, explanation or anything. Please, feel free to talk. I will never down-vote anyone who is trying to help me.
NOTE : this is the original C code that I used to make the dll file : http://stjarnhimlen.se/snippets/eval.c

The number -9.255963134931783E61 has the internal representation 0xCCCCCCCCCCCCCCCC, which strongly suggests that it is an uninitialised value.
Since you don't check the return value from evaluate, that suggests that it is returning an error condition, because in that case, evaluate does notset the value pointed to by its second argument.

I have noticed that the code is missing something. I revised it, and I remembered that a dll file is only loaded once when the program starts, so all the variables are being deleted or cleaned up. That caused the returned value to be odd and repeated continuously after the used arrays are full. So, I created a function to clear :
void clear() {
for (int i = 0; i!=256 ; i++) {
op_stack[i] = NULL;
arg_stack[i] = NULL;
token[i] = NULL;
}
op_sptr = 0;
arg_sptr = 0;
parens = 0;
state = 0;
}

Related

Junit did not show any results using IntelliJ for UCB cs61B (org.junit.Assert.assertArrayEquals() )

I am studying CS61B - UCB on my own, and I am a beginner in using IntelliJ and Junit4.12. I found there is no result for my org.junit.Assert.assertArrayEquals()
while in the video there is something shows like this
in the Run Window.
Here is the code for TestSort.java
import static org.junit.Assert.*;
import org.junit.Test;
/** Tests the the Sort class. */
public class TestSort {
/** Test the Sort.sort method. */
#Test
public void testSort() {
String[] input = {"i", "have", "an", "egg"};
String[] expected = {"an", "egg", "have", "i"};
Sort.sort(input);
if (input != expected)
{
System.out.println("something wrong!");
}
org.junit.Assert.assertArrayEquals(expected, input);
}
#Test
public void testFindSmallest() {
String[] input = {"i", "have", "an", "egg"};
int expected = 2;
int actual = Sort.findSmallest(input, 0);
assertEquals(expected, actual);
String[] input2 = {"there", "are", "many", "pigs"};
int expected2 = 2;
int actual2 = Sort.findSmallest(input2, 2);
assertEquals(expected2, actual2);
}
#Test
public void testSwap() {
String[] input = {"i", "have", "an", "egg"};
int a = 0;
int b = 2;
String[] expected = {"an", "have", "i", "egg"};
Sort.swap(input, a, b);
assertArrayEquals(expected, input);
}
}
Here is the code for Sort.java
public class Sort {
public static void sort(String[] x) {
sort(x, 0);
}
private static void sort(String[] x, int start) {
if (start == x.length) {
return;
}
int smallestIndex = findSmallest(x, start);
swap(x, start, smallestIndex);
sort(x, start + 1);
}
public static void swap(String[] x, int a, int b) {
String temp = x[a];
x[a] = x[b];
x[b] = temp;
}
public static int findSmallest(String[] x, int start) {
int smallestIndex = start;
for (int i = start; i < x.length; i += 1) {
int cmp = x[i].compareTo(x[smallestIndex]);
if (cmp < 0) {
smallestIndex = i;
}
}
return smallestIndex;
}
}
I think the function for Junit is to get the green part which shows how my codes work and get the result of whether two of my Strings are equal or not.
Another question about the IntelliJ is whether there is any difference between I RUN it and using the terminal to compile and operate it? Because when I use terminal, it will show something like this
enter image description here
I have googled a lot about this, it always said like I did not applied the Junit.jar into classpath. I have checked I have added the library.enter image description here
fyi, the you can get the library here enter link description here
I debugged the testSort function and it goes well for the input part and the sort functions part. while it gives me the hint that enter image description here, I chosed Download, it showed sources not found enter image description here, and when I chose sources from exist files enter image description here, it keeps attaching....How can I solve this problem?
You're code may not be running as you expected, but it is running exactly as a more experienced Java dev would expect. Let me explain...
You've discovered the behavior of the = operator (or more precisely in this case, !=) that often trips up less experienced Java engineers. The = operator doesn't know how to work with arrays so it falls back to comparing references. In your case it is comparing input and expected to see if they reference the exact same object. In your code both input and expected are declared as new arrays and therefor are different, individual objects; they do not reference the same object.
As for assertArrayEquals it likely doesn't use the = operator at all. While I haven't looked at the source code for that method I'd venture to guess that it first checks reference equality (are they both referencing the same object, then checks to see if they are both arrays and then checks to see whether each element of expected is also in input.
Arrays can add to the equality confusion because there are many definitions of equality. Equality could be defined as...
both arrays having the same number of elements in the same order
both arrays having the same number of elements, but different order
one array having 5 elements while the other having 10 elements where all 5 elements of the first array are also in the second array
etc.
One suggestion I have that might help you better understand this issue (as well as many more issues you are likely to face in the future) is to look at the source code of the method that's not working as you expect it to work, assertArrayEquals in this case. IntelliJ allows you to navigate to the source code, or if the source code is not available, look at the decompiled byte code. On a Mac just Command-click on the method. In Windows it might be Control-click??? (sorry, IntelliJ has so many different shortcut sets I can't be more specific.)
Further info on this topic...
What is the difference between == vs equals() in Java?
https://javabeginnerstutorial.com/core-java-tutorial/java-equals-method-vs-operator/

For loop and if statement within a method

I am new to using java and am having some issues in my java class right now and will be needing help with my specific code. I try to look at others questions on here all the time but it's never exactly what I need. Here are my directions:
Create a Java file called CompoundInterestYourLastName. Write a method called computeBalance() that computes the balance of a bank account with a given initial balance and interest rate, after a given number of years. Assume interest is compounded yearly.
Use a loop to control the iterations through the years in your method.
Your method should return a double value.
In your main method, run the following tests to verify your method is working correctly.
System.out.printf("Your total is $%.2f", computeBalance(1000, .045, 3));
// should return $1141.17
I am using eclipse and my only current error is in the comments. I also want some general tips and let me know if my logic is wrong. It probably is. :D
Here is what I have currently although I have been trying different things:
import java.util.Scanner;
import java.lang.Math;
public class CompoundInterestTidwell {
public static void main(String[] args) {
double compInt = computeBalance(1000, 0.045, 3);
System.out.printf("Your new balance is $%.2f", compInt);
}
// Getting arror for line of code below.
// Error: This method must return a result of type double
public static double computeBalance(int P, double r, int t) {
// Formula for compounding interest
// A = P(1+(r/n))^(n(t))
// The examples to check my math had rate already divided by 100 so I left out r/n.
for(int c = 0; c <= t; c++ ) {
// deleted 'n' from equation because it need to equal 1 anyways.
double compInt = Math.pow(P*(1+r), t);
if (c < t) {
c++;
return compInt;
}
}
}
}
Thanks.
Your function computeBalance doesn't guarantee to return a value, because the only return statement is in an if clause, within a loop (making it two conditions deep).
This is a thing the compiler is warning you about. Basically it scans your code and makes sure that a function declared as double will actually return a valid value of type double and so on.
If you add a return statement at the end of the body in the function (or throw an error) it should compile.
I am not exactly sure what your function does in technical terms, but I've rewritten it so it should return the same value, but should now actually compile.
public static double computeBalance(int P, double r, int t) {
// Formula for compounding interest
// A = P(1+(r/n))^(n(t))
// The examples to check my math had rate already divided by 100 so I left out r/n.
double compInt = 0; // Declare compInt outside the loop.
for(int c = 0; c <= t; c++ ) {
// deleted 'n' from equation because it need to equal 1 anyways.
compInt = Math.pow(P*(1+r), t);
if (c < t) {
c++;
break; // Break instead of return, will immediately
// go to the return statement outside the loop.
}
}
return compInt; // Moved the return statement to outside the loop so
// the function always will return a double.
}

Trouble with recursive method java

basically I have a brute force password guesser(I realize it's not very efficient) I have a process I want to make into a recursive method that i can pass a length integer and it will run with that amount of characters.
here is the code:
public static void generatePassword(int length)
{
// should be a recusive function learn how to do that
// 1 interval
for(int i =32;i<127;i++)// ascii table length
{
System.out.println((char)i);
}
// 2 interval
for(int z =32;z<127;z++)// ascii table length
{
for(int q =32;q<127;q++)// ascii table length
{
System.out.println((char)z+""+(char)q);
}
}
// 3 interval
for(int w =32;w<127;w++)// ascii table length
{
for(int o =32;o<127;o++)// ascii table length
{
for(int g =32;g<127;g++)// ascii table length
{
System.out.println((char)w+""+(char)o+""+(char)g);
}
}
}
}
the intervals return a string with that length example: 3rd interval will return every possible string combination with a length of 3. if anyone can help me automate this process and explain(i would like to learn rather then copy and paste) that would be great ! :)
A recursive method is a method that calls itself, it has a base-condition (also called stop condition) which prevents it from going into an infinite loop.
Lets take the first interval as an example:
for(int i = 32; i < 127; i++) { // ascii table length
System.out.println((char)i);
}
we can create a recursive method that'll do the same thing:
private void interval1(int i) {
if (i < 32 || i >= 127) return;
System.out.println((char)i);
interval1(i + 1);
}
in order to use it for our use-case, we should call this method with i=32: interval(32)
Hope this helps!
The function
Note that this will be EXTREMELY INEFFICIENT. This shouldn't ever be done in practice, since the number of String objects created is MIND-BOGGLINGLY HUGE (see bottom of answer)
public void recursivePrint(String prefix, int levels) {
if (levels <= 1) {
for (int i = 33; i < 127; ++i) {
System.out.println(prefix+(char)i);
}
} else {
for (int i = 33; i < 127; ++i) {
recursivePrint(prefix+(char)i, levels-1);
}
}
}
Then you call it with:
recursivePrint("", 5); // for printing all possible combinations of strings of length 5
The way it works
Each call to a function has it's own memory, and is stored seperately. When you first call the function, there is a String called prefix with a value of "", and an int called 'levels' which has a value of 5. Then, that function calls recursivePrint() with new values, so new memory is allocated, and the first call will wait until this new call has finished.
This new call has a String called prefix with a value of (char)34+"", and a levels with a value of 4. Note that these are completely separate instances of these variables to the first function call because remember: each function call has it's own memory (the first call is waiting for this one to finish). Now this second call makes another call to the recursivePrint() function, making more memory, and waiting until this new call finishes.
When we get to levels == 1, there is a prefix built up from previous calls, and all that remains is to use that prefix and print all the different combinations of that prefix with the last character changing.
Recursive methods are highly inefficient in general, and in this case especially.
Why you should never use it
This method is not just inefficient, though; it's infeasible for anything useful. Let's do a calculation: how many different possibilities are there for a string with 5 characters? Well there's 127-33=94 different characters you want to choose, then that means that you have 94 choices for each character. Then the total number of possibilities is 94^5 = 7.34*10^9 [that's not including the 5+ bytes to store each one] (to put that in perspective 4GB of RAM is around 4*10^9 bytes)
Here is your method implemented using recursion:
public static void generatePassword(int length, String s) {
if (length == 0) {
System.out.println(s);
return;
}
for (int i = 32; i < 127; i++) {
String tmp = s+((char) i);
generatePassword(length - 1, tmp);
}
}
All you have to do is to pass length and initial String (ie "") to it.
At if statement there is checked, if recursion should be stopped (when length of generated password is equals to expected).
At for-loop there is new character added to actual String and the method is invoked with shorter length and a new String as an argument.
Hope it helps.

UVa Online Judge 100th (3n+1) uDebug shows everything as correct but wrong answer

This is my first UVa submission so I had a few problems in the way. The biggest hurdle that took my time so far was probably getting all the formats correctly (I know, shouldn't have been too hard but I kept getting runtime error without knowing what that actually meant in this context). I did finally get past that runtime error, but I still get "Wrong answer."
Listed below are the things I've done for this problem. I've been working on this for the last few hours, and I honestly thought about just dropping it altogether, but this will bother me so much, so this is my last hope.
Things I've done:
considered int overflow so changed to long at applicable places
got the whole list (1-1000000) in the beginning through memorization for computation time
submitted to uDebug. Critical input and Random input both show matching output.
submitted to to UVa online judge and got "Wrong Answer" with 0.13~0.15 runtime.
Things I'm not too sure about:
I think I read that UVa doesn't want its classes to be public. So I left mine as class Main instead of the usual public class Main. Someone from another place mentioned that it should be the latter. Not sure which one UVa online judge likes.
input. I used BufferedReader(new InputStreaReader (System.in)) for this. Also not sure if UVa online judge likes this.
I thought my algorithm was correct but because of "Wrong answer," I'm not so sure. If my code is hard to read, I'll try to describe what I did after the code.
Here is my code:
class Main {
public static int mainMethod(long i, int c, List<Integer> l) {
if (i==1)
return ++c;
else if (i%2==0) {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i/2, c, l);
}
}
else {
if (i<1000000&&l.get((int)i)!=null)
return l.get((int)i)+c;
else {
c++;
return mainMethod(i*3+1, c, l);
}
}
}
public static int countMax(int x, int y, List<Integer> l) {
int max=0;
if (x>y) {
int temp = x;
x= y;
y = temp;
}
for (int i=x; i<=y; i++) {
if (l.get(i)>max)
max = l.get(i);
}
return max;
}
public static void main(String[] args) {
List<Integer> fixed = Arrays.asList(new Integer[1000000]);
for (long i=1; i<1000000; i++) {
fixed.set((int)i, mainMethod(i,0,fixed));
}
String s;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while ((s = br.readLine())!=null) {
int x = -1;
int y = -1;
for (String split : s.split("\\s+")) {
if (!split.equals("\\s+") && x==-1) {
x = Integer.parseInt(split);
} else if (!split.equals("\\s+") && x!=-1) {
y = Integer.parseInt(split);
}
}
if (x!=-1&&y!=-1)
System.out.println(Integer.toString(x) + " " + Integer.toString(y) + " " + Integer.toString(countMax(x,y,fixed)));
}
} catch (IOException e) {
} catch (NumberFormatException e) {
}
}
}
I apologize for generic names for methods and variables. mainMethod deals with memorization and creating the initial list. countMax deals with the input from the problem (15 20) and finding the max length using the list. The for loop within the main method deals with potential empty lines and too many spaces.
So my (if not so obvious) question is, what is wrong with my code? Again, this worked perfectly fine on uDebug's Random Input and Critical Input. For some reason, however, UVa online judge says that it's wrong. I'm just clueless as to where it is. I'm a student so I'm still learning. Thank you!
Haven't spotted your error yet, but a few things that may make it easier to spot.
First off:
int goes to 2^31, so declaring i in mainMethod to be long is unnecessary. It also states in the problem specification that no operation will overflow an int, doesn't it? Getting rid of the extraneous longs (and (int) casts) would make it easier to comprehend.
Second:
It's probably clearer to make your recursive call with c + 1 than ++c or doing c++ before it. Those have side effects, and it makes it harder to follow what you're doing (because if you're incrementing c, there must be a reason, right?) What you're writing is technically correct, but it's unidiomatic enough that it distracts.
Third:
So, am I missing something, or are you never actually setting any of the values in the List in your memoization function? If I'm not blind (which is a possibility) that would certainly keep it from passing as-is. Wait, no, definitely blind - you're doing it in the loop that calls it. With this sort of function, I'd expect it to mutate the List in the function. When you call it for i=1, you're computing i=4 (3 * 1 + 1) - you may as well save it.

Recursive binary search -- Java

I've searched extensively online but all solutions I've found use two parameters to keep track of the size of the area being used. This would be easy if I was allowed to do that, but I'm not. As you can see below, the code lacks a stop value, because I have no idea how to retain the original information.
This is the code on Wikipedia, you can see they use imin and imax for tracker variables: http://en.wikipedia.org/wiki/Binary_search_algorithm#Recursive
My (very incorrect) code is below. The mid variable doesn't mean anything, because I don't know how to set low and high correctly if I'm not allowed to have any extra arguments in the function.
public static int findRecursiveB( String s, char c)
{
int low = 0;
int high = s.length()-1;
int mid = (low+high)/2;
if (s.charAt(mid) < c) {
return findRecursiveB(s.substring(low, mid), c);
}
else if (s.charAt(mid) >= c) {
return findRecursiveB(s.substring(mid+1, high), c);
}
else return mid;
}
One crucial point here is what does the original String s contain? For this to work, it has to be a sorted String, meaning that the characters in the String must be in order. Specifically, it looks like you've written code that expects s to be sorted in reverse order. Otherwise, unless I'm totally missing something, your code does exactly what it is supposed to: no need to pass extra params because you are passing in the substring on each recursive call.
Otherwise, good job.

Categories