I want to find the zero points of a sine function. The parameter is a interval [a,b]. I have to it similar to binary search.
Implement a function that searches for null points in the sinus function in a interval between a and b. The search-interval[lower limit, upper limit] should be halved until lower limit and upper limit are less then 0.0001 away from each other.
Here is my code:
public class Aufg3 {
public static void main(String[] args) {
System.out.println(zeropoint(5,8));
}
private static double zeropoint(double a, double b){
double middle = (a + b)/2;
if(Math.sin(middle) < 0){
return zeropoint(a,middle);
}else if(Math.sin(middle) > 0){
return zeropoint(middle,b);
}else{
return middle;
}
}
}
It gives me a lot of errors at the line with return zeropoint(middle,b);
In a first step I want to find just the first zero point in the interval.
Any ideas?
Fundamental problems that everybody has overlooked:
we don't always want to return a result (imagine finding the zero points of the sine function between pi/4 and 3pi/4, there aren't any).
in any arbitrary range range there may be several zeros.
Clearly what is needed is a (possibly empty) set of values.
So pseudocode of the function really asked for (not using Java as this is homework):
Set zeropoint(double a, double b)
{
double middle = mid point of a and b;
if a and be less than 0.0001 apart
{
if (sin(a) and sin(b) are on opposite sides of 0)
{
return set containing middle
}
else
{
return empty set
}
}
else
{
return union of zeropoint(a, middle) and zeropoint(middle, b)
}
}
Simply saying "it gives me errors" is not very helpful. What kind of errors? Compile errors or uncaught exceptions at runtime?
For your code, two things stand out as possible problems:
the variable mitte does not appear to be declared anywhere.
you are using > and < to compare reals. While that is ok by itself, it is better to check for 0 using a tolerance instead of relying on < and >, to avoid problems due to floating point precision. For all practical purposes -0.000000000001 is 0.
There might be other problems as well, I just wrote down the ones that jumped out at first glance.
Edit:
Apparently the mitte was due to an error in pasting the code by the OP (and has since been corrected). As other answers have pointed out, the code falls in to infinite recursion. This is because the recursion calls are on the wrong intervals.
One thing to note, the sin function can be monotonically increasing for one choice of a and b, and monotonically decreasing at some other interval. e.g. It is increasing over [0,pi/2] and it is decreasing over [pi/2,3*pi/2]. Thus the recursive calls need to changed according to the original interval the search is being made in. For one interval Math.sin(middle)<0 implies that Math.sin(x)<0 for all x in [a,middle], but for some other interval the opposite is true. This probably why this falls into infinite recursion for the interval that you are trying. I think this works over some other interval where sin is actually decreasing. Try calling your function over [pi/2,3*pi/2].
I'm guessing you are getting stack overflow errors at runtime. The < and > signs are reversed. Also, you should use .0001 and not 0 to compare to.
Edit 1:
Actually, your basic algorithm has issues. What happens if there are more than one zero in the interval? What happens if sin(a) and the sin(mitte) have the same sign? What happens if there are no zeros in the interval?
Edit 2:
Ok, so I did the problem and fundamentally, your solution is problematic; I would try to start over in thinking how to solve it.
The major issue is that there could be multiple zeros in the interval and you are trying to find each of them. Creating a function that returns a type double can only return one solution. So, rather than creating a function to return double, just return void and print out the zeros as you find them.
Another hint: You are supposed to continue searching until a and b are within .0001 of each other. Your final solution will not use .0001 in any other way. (I.e, your check to see if you found a zero should not use the .0001 tolerance and nor will it use 0 exactly. Think about how you will really know if you have found a zero when abs(a-b) is less than .0001.
Did you read the assignment to the end? It says:
The search-interval[lower limit, upper
limit] should be halved until lower
limit and upper limit are less then
0.0001 away from each other.
So you can't expect Math.sin(middle) to return exactly zero because of floating point precision issues. Instead you need to stop the recursion when you reach 0.0001 precision.
My guess is that you're running into a StackOverflowError. This is due to the fact that you're never reaching a base case in your recursion. (Math.sin(middle) may never equal exactly 0!)
Your exercise says
[...] until lower limit and upper limit are less then 0.0001 away from each other.
So, try putting this in top of your method:
double middle = (a + b)/2;
if (b - a < 0.0001)
return middle;
Besides some floating point problems other have mentioned, your algorithm seems to be based on the implicit assumptions that:
sin(a) is positive
sin(b) is negative, and
sin(x) is a decreasing function on the interval [a,b].
I see no basis for these assumptions. When any of them is false I don't expect your algorithm to work. They are all false when a=5 and b=8.
if(Math.sin(mitte) < 0){
Where is mitte declared? Isn't mitte middle?
private static double zeropoint(double a, double b){
double middle = (a + b)/2;
double result = middle;
if (Math.abs(a - b) > 0.0001) {
double sin = Math.sin(middle);
if (Math.abs(sin) < 0.0001) {
result = middle;
} else if (sin > 0) {
result = zeropoint(a, middle);
} else {
result = zeropoint(middle, b);
}
}
return result;
}
something like this i think - just to fix first errors
Related
I want to find whether a given number is a power of two in a mathematical way, not with a bitwise approach. Here is my code:
private static double logBaseTwo(final double x) {
return Math.log(x) / Math.log(2);
}
private static double roundToNearestHundredThousandth(final double x) {
return Math.round(x * 100000.0) / 100000.0;
}
private static boolean isInteger(final double x) {
return (int)(Math.ceil(x)) == (int)(Math.floor(x));
}
public static boolean isPowerOfTwo(final int n) {
return isInteger(roundToNearestHundredThousandth(logBaseTwo(n)));
}
It incorrectly returns true for certain numbers, such as 524287. Why is that?
Your code fails because you may need more precision than you allow to capture the difference between the logs of BIG_NUMBER and BIG_NUMBER+1
The bitwise way is really best, but if you really want to use only "mathy" operations, then the best you can do is probably:
public static boolean isPowerOfTwo(final int n) {
int exp = (int)Math.round(logBaseTwo(n));
int test = (int)Math.round(Math.pow(2.0,exp));
return test == n;
}
This solution does not require any super-fine precision, and will work fine for all positive ints.
This is truly horrifyingly bad code, and I have no idea what you are trying to do. You seem to be trying to check if the log base 2 of n is an integer. Instead I would write a loop:
while (n>1) {
m = (n/2) * 2
if (n!=m){
return false;
}
n /=2;
}
return true;
The solution seems more complicated than it should be. I don't get the 100000d parts - seems to potentially cause problems when converting to ceiling.
This is the simple solution that works for all cases:
public static boolean isPowerOfTwo(int n) {
return Math.ceil(Math.log(n)/Math.log(2)) == Math.floor(Math.log(n)/Math.log(2));
}
Originally I had a problem using Math.log in my computations. I switched to Math.log10 and the problem went away. Although mathematically, any logB of base B should work, the nature of floating point math can be unpredictable.
Try this.
public static boolean isPowerOfTwo(int n) {
return n > 0 && Integer.highestOneBit(n) == Integer.lowestOneBit(n);
}
If you prefer to use logs you can do it this way.
public static boolean isPowerOfTwo(int n) {
return n > 0 && (Math.log10(n)/Math.log10(2))%1 == 0;
}
doubles and floats have, respectively, 64-bit and 32-bit precision. That means they can hold at the very most 18446744073709551616 unique numbers. That's a lot of numbers, but not an infinite amount of them. At some point (in fact, that point occurs about at 2^52), the 'gap' between any 2 numbers which are part of the 18446744073709551616 representable ones becomes larger than 1.000. Similar rules apply to small numbers. Math.log does double based math.
Secondarily, ints are similarly limited. They can hold up to 4294967296 different numbers. For ints it's much simpler: Ints can hold from -2147483648 up to 2147483647. If you try to add 1 to 2147483647, you get -2147483648 (it silently wraps around). It's quite possible you're running into that with trying to convert such a large number (your double times 10000d) to an int first.
Note that ? true : false (as in the original version of the question) is literally completely useless. the thing to the left of the question mark must be a boolean, and booleans are already true or false, that's their nature.
See the other answers for simpler approaches to this problem. Although, of course, the simplest solution is to simply count bits in the number. If it's precisely 1 bit, it's a power of 2. If it's 0 bits, well, you tell me if you consider '0' a power of 2 :)
I am currently working on a method to do an exponentiation calculation using recursion. Here is what I have so far:
public static long exponentiation(long x, int n) {
if (n == 0) {
return 1;
} else if (n == 1) {
return x;
// i know this doesn't work since im returning long
} else if (n < 0) {
return (1 / exponentiation(x, -n));
} else {
//do if exponent is even
if (n % 2 == 0) {
return (exponentiation(x * x, n / 2));
} else {
// do if exponent is odd
return x * exponentiation(x, n - 1);
}
}
}
I have two issues. First issue is that I cannot do negative exponent's, this is not a major issue since I am not required to do negative exponents. Second issue, is certain computations give me the wrong answer. For example 2^63 gives me the correct value, but it gives me a negative number. And 2^64 and on just give me 0. Is there anyway for me to fix this? I know that I could just switch the long's to doubleand my method will work perfectly. However, my professor has required us to use long. Thank you for your help!
The maximum value a long can represent is 2^63 -1. So if you calculate 2^63, it is bigger then what a long can hold and wraps around. Long is represented using twos-complement.
Just changing long to double doesn't exactly work. It changes the semantics of the method. Floating-point numbers have limite precision. With a 64-bit floating point number, you can still only represent the same amount of numbers as with a 64-bit integer. They are just distributed differently. a long can represent every whole number bewteen -2^63 and 2^63-1. A double can represent fractions of numbers as well, but at high numbers, it can't even represent every number.
For example, the next double you can represent after 100000000000000000000000000000000000000000000000000 is 100000000000000030000000000000000000000000000000000 - so you are missiong a whopping 30000000000000000000000000000000000 you can not represent with a double.
You are trying to fix something that you shouldn't bother with fixing. Using a long, there is a fixed maximum return value your method may return. Your method should clearly state what happens if it overflows, and you might want to handle such overflows (e.g. using Math#multiplyExactly), but if long is the return value you are supposed to return, then that is what you should be using.
You could hold the result in an array of longs, let's call it result[]. At first, apply the logic to result[0]. But, when that value goes negative,
1) increment result[1] by the excess.
2) now, your logic gets much messier and I'm typing on my phone, so this part is left as an exercise for the reader.
3) When result[1] overflows, start on result[2]...
When you print the result, combine the results, again, logic messy.
I assume this is how BigInteger works (more or less)? I've never looked at that code, you might want to.
But, basically, Polygnone is correct. Without considerable workarounds, there is an upper limit.
The rules are that I have to return the largest number, so pretty much the user wants to find the biggest number. Split the array in half or close to it and find the biggest value from the array in the lower half and find the biggest value in the high half. I just started learning recursion and this problem is giving me nightmares.
public static double getBiggest(double[] a, int low, int high)
{
int mid = (low+high)/2;
double one = 0;
double two = 0;
if(a == null || a.length == 0 || low > high)
throw new IllegalArgumentException();
//How do I loop to find the biggest?
//A way to narrow down a big number of array values into a single one
one = getBiggest(a,low,mid);
two = getBiggest(a,mid,high);
if(one >= two)
return one;
else
return two;
return -1;
}
Your code is already pretty close, but since getBiggest always calls getBiggest(), it will never stop.
Before the recursive call, do something like this
if (low >= high)
{
return a[low];
}
That still leaves a little problem: When high == low+1, mid == low, so getBiggest(a,mid,high) will be the same size as the call you're in. Recursing with the same arguments again means that it will never stop.
Your recursive calls should be like:
one = getBiggest(a,low,mid);
two = getBiggest(a,mid+1,high);
That way both of the recursive calls are guaranteed to be smaller.
Finally, the conditional part at the end works, but the return a[mid] never happens. You should rewrite it like:
if(one >= two)
return one;
else
return two;
In English, the algorithm works like this:
If there's only one element, return it. Otherwise;
Get the biggest element in the first half (the first recursive call), then
Get the biggest element in the second half (the second recursive call), then
return whichever is bigger.
A recursive solution to a problem is made from solutions to smaller versions of the same problem.
Any recursive algorithm must ALWAYS have a base case - if the problem is small enough that it can be solved trivially then that must be done instead. The function must not invariably call itself recursively, otherwise you are guaranteed to get infinite recursion, which in Java means a StackOverflowException. In this case you always call getBiggest as long as the arguments are valid so that is your problem. You wrote "If the low to high section is 3 or bigger" but there is no such if statement in your code. Adding one will allow you to avoid recursion when low and high meet.
Your implementation has two problems:
It is not doing the arguments checking correctly - the check needs to happen at the top, and
You are missing the base case. Any recursive program must specify what to do when you are down to one or two items; your program is not doing it.
You need to add a condition at the top to see if high minus low is two or less. If it is one, return the number at the low end; if there are two numbers, pick the max and return it.
I'm trying to find the most precise value by calling a method many times. How can I check when the nth iteration will give a value of precision 8 digits. My method returns a double each time I call it, but I want to stop calling it when the result has 8 digits of accuracy in it.
For example, if I call the method getValue() 20 times, and on the 20th time it has an answer that has 8 digits, how do I check the answer and stop the code?
My method is too long to post, so a general explanation should suffice.
The Problem is as follows:
Use the power method to calculate the largest eigenvalue of the Leslie matrix A. The iteration of the power method should stop when you get 8 digits of accuracy.The Leslie Matrix Model can be written as
n(k + 1) = An(k), k = 0, 1, 2,... and with some n(0) given.
double is never going to be precise enough in this way. The only way to know the accuracy of your answer is by doing a mathematical analysis of the operation you're doing and stopping when the error is guaranteed to be less than a certain amount.
However, there is a little bit of a trick if you know your analysis is going to converge. You can compare successive values, and see how large the difference is. Here's some pseudocode:
while(true) {
nextValue = computeNextValue(previousValue);
if(Math.abs(previousValue - nextValue) < ERROR_THRESHOLD) {
break;
}
previousValue = nextValue;
}
#user58697 makes a great point in the comments:
Even if the sequence converges, successive difference may stop the process too early. Knowing the convergence rate is vital.
Keep this in mind when writing your program.
Honestly, I do not believe that there is a generic answer. How do you know that the answer 7.9999999 is more precise than 8.0 (which could be 8.00000000000000) ? It probably depends very much on the problem you want to solve, I guess.
You may use the following hack to check the fractional part. Here is the complete code -
public class FractionCheck{
public static void main(String[] args){
int length1 = findFractionLegth(423423.98476527);
int length2 = findFractionLegth(428294.31231);
System.out.println(length1);
System.out.println(length2);
}
public static int findFractionLegth(double number){
String numberStr = Double.toString(number);
String fractionalStr = numberStr.substring(numberStr.indexOf('.')+1);
return fractionalStr.length();
}
}
The findFractionLegth(double number) method calculate the fractional part of a double.
I have just started my long path to becoming a better coder on CodeChef. People begin with the problems marked 'Easy' and I have done the same.
The Problem
The problem statement defines the following -:
n, where 1 <= n <= 10^9. This is the integer which Johnny is keeping secret.
k, where 1 <= k <= 10^5. For each test case or instance of the game, Johnny provides exactly k hints to Alice.
A hint is of the form op num Yes/No, where -
op is an operator from <, >, =.
num is an integer, again satisfying 1 <= num <= 10^9.
Yes or No are answers to the question: Does the relation n op num hold?
If the answer to the question is correct, Johnny has uttered a truth. Otherwise, he is lying.
Each hint is fed to the program and the program determines whether it is the truth or possibly a lie. My job is to find the minimum possible number of lies.
Now CodeChef's Editorial answer uses the concept of segment trees, which I cannot wrap my head around at all. I was wondering if there is an alternative data structure or method to solve this question, maybe a simpler one, considering it is in the 'Easy' category.
This is what I tried -:
class Solution //Represents a test case.
{
HashSet<SolutionObj> set = new HashSet<SolutionObj>(); //To prevent duplicates.
BigInteger max = new BigInteger("100000000"); //Max range.
BigInteger min = new BigInteger("1"); //Min range.
int lies = 0; //Lies counter.
void addHint(String s)
{
String[] vals = s.split(" ");
set.add(new SolutionObj(vals[0], vals[1], vals[2]));
}
void testHints()
{
for(SolutionObj obj : set)
{
//Given number is not in range. Lie.
if(obj.bg.compareTo(min) == -1 || obj.bg.compareTo(max) == 1)
{
lies++;
continue;
}
if(obj.yesno)
{
if(obj.operator.equals("<"))
{
max = new BigInteger(obj.bg.toString()); //Change max value
}
else if(obj.operator.equals(">"))
{
min = new BigInteger(obj.bg.toString()); //Change min value
}
}
else
{
//Still to think of this portion.
}
}
}
}
class SolutionObj //Represents a single hint.
{
String operator;
BigInteger bg;
boolean yesno;
SolutionObj(String op, String integer, String yesno)
{
operator = op;
bg = new BigInteger(integer);
if(yesno.toLowerCase().equals("yes"))
this.yesno = true;
else
this.yesno = false;
}
#Override
public boolean equals(Object o)
{
if(o instanceof SolutionObj)
{
SolutionObj s = (SolutionObj) o; //Make the cast
if(this.yesno == s.yesno && this.bg.equals(s.bg)
&& this.operator.equals(s.operator))
return true;
}
return false;
}
#Override
public int hashCode()
{
return this.bg.intValue();
}
}
Obviously this partial solution is incorrect, save for the range check that I have done before entering the if(obj.yesno) portion. I was thinking of updating the range according to the hints provided, but that approach has not borne fruit. How should I be approaching this problem, apart from using segment trees?
Consider the following approach, which may be easier to understand. Picture the 1d axis of integers, and place on it the k hints. Every hint can be regarded as '(' or ')' or '=' (greater than, less than or equal, respectively).
Example:
-----(---)-------(--=-----)-----------)
Now, the true value is somewhere on one of the 40 values of this axis, but actually only 8 segments are interesting to check, since anywhere inside a segment the number of true/false hints remains the same.
That means you can scan the hints according to their ordering on the axis, and maintain a counter of the true hints at that point.
In the example above it goes like this:
segment counter
-----------------------
-----( 3
--- 4
)-------( 3
-- 4
= 5 <---maximum
----- 4
)----------- 3
) 2
This algorithm only requires to sort the k hints and then scan them. It's near linear in k (O(k*log k), with no dependance on n), therefore it should have a reasonable running time.
Notes:
1) In practice the hints may have non-distinct positions, so you'll have to handle all hints of the same type on the same position together.
2) If you need to return the minimum set of lies, then you should maintain a set rather than a counter. That shouldn't have an effect on the time complexity if you use a hash set.
Calculate the number of lies if the target number = 1 (store this in a variable lies).
Let target = 1.
Sort and group the statements by their respective values.
Iterate through the statements.
Update target to the current statement group's value. Update lies according to how many of those statements would become either true or false.
Then update target to that value + 1 (Why do this? Consider when you have > 5 and < 7 - 6 may be the best value) and update lies appropriately (skip this step if the next statement group's value is this value).
Return the minimum value for lies.
Running time:
O(k) for the initial calculation.
O(k log k) for the sort.
O(k) for the iteration.
O(k log k) total.
My idea for this problem is similar to how Eyal Schneider view it. Denoting '>' as greater, '<' as less than and '=' as equals, we can sort all the 'hints' by their num and scan through all the interesting points one by one.
For each point, we keep in all the number of '<' and '=' from 0 to that point (in one array called int[]lessAndEqual), number of '>' and '=' from that point onward (in one array called int[]greaterAndEqual). We can easily see that the number of lies in a particular point i is equal to
lessAndEqual[i] + greaterAndEqual[i + 1]
We can easily fill the lessAndEqual and greaterAndEqual arrays by two scan in O(n) and sort all the hints in O(nlogn), which result the time complexity is O(nlogn)
Note: special treatment should be taken for the case when the num in hint is equals. Also notice that the range for num is 10^9, which require us to have some forms of point compression to fit the array into the memory