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 an output operation from JEval that is an string with the float imprecision, something like "1.56700000001". I need some approach to hold the maximum precision but correcting the float imprecision. Perhaps some efficient algorithm that makes the most exact thing without being wrong.
If I´m not wrong, any double with not exact binary representation will be output´d if so in a String of length() 18, with the precision = (14 minus - point char - integer part).
So we can round to the precision-1 (last) digit when the string is clearly using all the bits without trailing zeroes (as JEval dont show them, this means when length() == 18 ).
The only problem would be if the original string has a real expected full value and needs not rounding, in that case we only would loose one digit of precision.
What do you think of this approach. Is it a better way?
For example:
import java.math.BigDecimal;
import java.math.MathContext;
public class test {
private final static int THREESHOLD = 3; // num of decimals from which
// we consider that they represent a floating
// representation inaccuracy in case every double´s
//digit is used with no traliing zeroes ending
public static void main(String[] args){
String[] JEvalOutput = {"1.5555000000000001", //Rounding is needed
"234455555.29", //Rounding is not needed
"455656.45599999998", //Rounding is needed
"111132323232334.19", //Here there is a problem, should be rounded???
//Thats why we use THREESHOLD var, to distinguish when can we consider
"123456789012345678"};//Rounding is not needed
for (String aux : JEvalOutput){
int precision = aux.length()-(aux.contains(".")?1:0);
if (precision==17 && aux.contains(".") && aux.length()-aux.indexOf('.')-1 >THREESHOLD) precision--;
BigDecimal a = new BigDecimal(aux, new MathContext(precision)).stripTrailingZeros();
System.out.println(aux + " --> " + a.toPlainString()); //Only First and Third are rounded.
}
}
}
Prints:
1.5555000000000001 --> 1.5555
234455555.29 --> 234455555.29
455656.45599999998 --> 455656.456
111132323232334.19 --> 111132323232334.19 //If THREESHOLD was 1, then this would be 111(...)34.2
123456789012345678 --> 123456789012345678
Is there any cleaner, best practice, professional solution?
This is what you want. You're welcome.
BigDecimal bd = new BigDecimal("123.4566661");
DecimalFormat df = new DecimalFormat("#.0#");
System.out.println(df.format(bd));
I am using java and have to deal with numbers larger than long (which is 64 bits). What should I use? What is the size of BigInteger in java?
As you mentioned in your question, you should use BigInteger.
They can be as large as you need - until you run out of memory.
What is the size of BigInteger in java?
That's a little bit tricky. The problem is that there is no clear specification of the limit in the javadocs.
The class uses an int[] to represent the magnitude. This means it could potentially represent numbers up to ((2^32)^(2^31 - 1).
The API has a method that returns the number as a 2's complement byte array. The limit for this is ((2^8)^(2^31 - 1).
The API has another method that returns the size of the number in bits ... as an int. This implies a limit of 2^(2^31 - 1) or maybe 2^(2^32).
In practice, these numbers are all so large that you will probably run into heap space limits (or CPU performance limits) first.
the problem is I have to find out the square root of a the number.
You should be able to find an algorithm for calculating square roots in your undergraduate maths text books (or Wikipedia). Coding it should be a simple task.
(I'd point you at example code, except that this smells like "homework", and I don't entirely trust the code that I found.)
Don't forget that most integers have an irrational square-root ...
you are looking either for the class BigDecimal or if you just need integers, than BigInteger. Its arbitrary precision, so the size changes based on how big the numbers are that you input
To find a square root of a BigInteger you have to do a google search with "-StackOverflow" answers omitted. https://www.google.com/search?q=java+extract+root+bignum&ie=utf-8&oe=utf-8#q=java+root+BigInteger+-stackoverflow.com+-stackexchange.com yields the first link to http://faruk.akgul.org/blog/javas-missing-algorithm-biginteger-sqrt/ Here is one algorithm. Java is supposed to be "write once, use everywhere". Well, some SO users believe that you must reinvent the wheel. Ask them for a module they answer "smells like a homework, do it yourself". And yes, BigInteger is half baked. It can't do logarithms or roots out of the box. It is extremely slow. The algorithm is given below.
BigInteger sqrt(BigInteger n) {
BigInteger a = BigInteger.ONE;
BigInteger b = new BigInteger(n.shiftRight(5).add(new BigInteger("8")).toString());
while(b.compareTo(a) >= 0) {
BigInteger mid = new BigInteger(a.add(b).shiftRight(1).toString());
if(mid.multiply(mid).compareTo(n) > 0) b = mid.subtract(BigInteger.ONE);
else a = mid.add(BigInteger.ONE);
}
return a.subtract(BigInteger.ONE);
}
import java.util.Scanner;
import java.math.BigDecimal;
public class Ha40 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
long d=scan.nextLong();
String st=" ";
st=scan.next();
st+= scan.nextLine();
// Write your code here.
System.out.println("String: " + st);
System.out.println("Double: " + d);
System.out.println("Int: " + i);
}
}
input are:2147483647
235345345345.234534
fsdfsdf sdf but ans is not getting upto the mark
Suppose I have a method to calculate combinations of r items from n items:
public static long combi(int n, int r) {
if ( r == n) return 1;
long numr = 1;
for(int i=n; i > (n-r); i--) {
numr *=i;
}
return numr/fact(r);
}
public static long fact(int n) {
long rs = 1;
if(n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
}
return rs;
}
As you can see it involves factorial which can easily overflow the result. For example if I have fact(200) for the foctorial method I get zero. The question is why do I get zero?
Secondly how do I deal with overflow in above context? The method should return largest possible number to fit in long if the result is too big instead of returning wrong answer.
One approach (but this could be wrong) is that if the result exceed some large number for example 1,400,000,000 then return remainder of result modulo
1,400,000,001. Can you explain what this means and how can I do that in Java?
Note that I do not guarantee that above methods are accurate for calculating factorial and combinations. Extra bonus if you can find errors and correct them.
Note that I can only use int or long and if it is unavoidable, can also use double. Other data types are not allowed.
I am not sure who marked this question as homework. This is NOT homework. I wish it was homework and i was back to future, young student at university. But I am old with more than 10 years working as programmer. I just want to practice developing highly optimized solutions in Java. In our times at university, Internet did not even exist. Today's students are lucky that they can even post their homework on site like SO.
Use the multiplicative formula, instead of the factorial formula.
Since its homework, I won't want to just give you a solution. However a hint I will give is that instead of calculating two large numbers and dividing the result, try calculating both together. e.g. calculate the numerator until its about to over flow, then calculate the denominator. In this last step you can chose the divide the numerator instead of multiplying the denominator. This stops both values from getting really large when the ratio of the two is relatively small.
I got this result before an overflow was detected.
combi(61,30) = 232714176627630544 which is 2.52% of Long.MAX_VALUE
The only "bug" I found in your code is not having any overflow detection, since you know its likely to be a problem. ;)
To answer your first question (why did you get zero), the values of fact() as computed by modular arithmetic were such that you hit a result with all 64 bits zero! Change your fact code to this:
public static long fact(int n) {
long rs = 1;
if( n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
System.out.println(rs);
}
return rs;
}
Take a look at the outputs! They are very interesting.
Now onto the second question....
It looks like you want to give exact integer (er, long) answers for values of n and r that fit, and throw an exception if they do not. This is a fair exercise.
To do this properly you should not use factorial at all. The trick is to recognize that C(n,r) can be computed incrementally by adding terms. This can be done using recursion with memoization, or by the multiplicative formula mentioned by Stefan Kendall.
As you accumulate the results into a long variable that you will use for your answer, check the value after each addition to see if it goes negative. When it does, throw an exception. If it stays positive, you can safely return your accumulated result as your answer.
To see why this works consider Pascal's triangle
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
which is generated like so:
C(0,0) = 1 (base case)
C(1,0) = 1 (base case)
C(1,1) = 1 (base case)
C(2,0) = 1 (base case)
C(2,1) = C(1,0) + C(1,1) = 2
C(2,2) = 1 (base case)
C(3,0) = 1 (base case)
C(3,1) = C(2,0) + C(2,1) = 3
C(3,2) = C(2,1) + C(2,2) = 3
...
When computing the value of C(n,r) using memoization, store the results of recursive invocations as you encounter them in a suitable structure such as an array or hashmap. Each value is the sum of two smaller numbers. The numbers start small and are always positive. Whenever you compute a new value (let's call it a subterm) you are adding smaller positive numbers. Recall from your computer organization class that whenever you add two modular positive numbers, there is an overflow if and only if the sum is negative. It only takes one overflow in the whole process for you to know that the C(n,r) you are looking for is too large.
This line of argument could be turned into a nice inductive proof, but that might be for another assignment, and perhaps another StackExchange site.
ADDENDUM
Here is a complete application you can run. (I haven't figured out how to get Java to run on codepad and ideone).
/**
* A demo showing how to do combinations using recursion and memoization, while detecting
* results that cannot fit in 64 bits.
*/
public class CombinationExample {
/**
* Returns the number of combinatios of r things out of n total.
*/
public static long combi(int n, int r) {
long[][] cache = new long[n + 1][n + 1];
if (n < 0 || r > n) {
throw new IllegalArgumentException("Nonsense args");
}
return c(n, r, cache);
}
/**
* Recursive helper for combi.
*/
private static long c(int n, int r, long[][] cache) {
if (r == 0 || r == n) {
return cache[n][r] = 1;
} else if (cache[n][r] != 0) {
return cache[n][r];
} else {
cache[n][r] = c(n-1, r-1, cache) + c(n-1, r, cache);
if (cache[n][r] < 0) {
throw new RuntimeException("Woops too big");
}
return cache[n][r];
}
}
/**
* Prints out a few example invocations.
*/
public static void main(String[] args) {
String[] data = ("0,0,3,1,4,4,5,2,10,0,10,10,10,4,9,7,70,8,295,100," +
"34,88,-2,7,9,-1,90,0,90,1,90,2,90,3,90,8,90,24").split(",");
for (int i = 0; i < data.length; i += 2) {
int n = Integer.valueOf(data[i]);
int r = Integer.valueOf(data[i + 1]);
System.out.printf("C(%d,%d) = ", n, r);
try {
System.out.println(combi(n, r));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Hope it is useful. It's just a quick hack so you might want to clean it up a little.... Also note that a good solution would use proper unit testing, although this code does give nice output.
You can use the java.math.BigInteger class to deal with arbitrarily large numbers.
If you make the return type double, it can handle up to fact(170), but you'll lose some precision because of the nature of double (I don't know why you'd need exact precision for such huge numbers).
For input over 170, the result is infinity
Note that java.lang.Long includes constants for the min and max values for a long.
When you add together two signed 2s-complement positive values of a given size, and the result overflows, the result will be negative. Bit-wise, it will be the same bits you would have gotten with a larger representation, only the high-order bit will be truncated away.
Multiplying is a bit more complicated, unfortunately, since you can overflow by more than one bit.
But you can multiply in parts. Basically you break the to multipliers into low and high halves (or more than that, if you already have an "overflowed" value), perform the four possible multiplications between the four halves, then recombine the results. (It's really just like doing decimal multiplication by hand, but each "digit" is, say, 32 bits.)
You can copy the code from java.math.BigInteger to deal with arbitrarily large numbers. Go ahead and plagiarize.
I just started Data Structures and Algorithms which is taught in Java. So far I've only learned C++ in my life so I'm still VERY new to using java.
Anyways I have a homework problem I'm a little stuck on:
Write a recursive method that returns the number of 1's in the binary representation of N. Use the fact that this is equal to the number of 1's in the representation of N/2 + 1, if N is odd.
Now i'm not sure how exactly to do this. I already have a function set up that takes an integer and converts it to binary and stores it in a string, yet the rest I'm kinda lost on.
If I can get some guidance, that would really help.
This is what I have so far:
import java.io.*;
public class Homework1Code {
static void prtbinary(String Molly, int size){
if(size <=0){
return;
}
}
public static void main(String[] args) {
int i = 38;
String binstr = Integer.toBinaryString(i);
System.out.println("The Original Decimal Number is: " + binstr);
prtbinary(binstr, binstr.length());
}
}
Thanks
This is not a hard problem to solve. What you need to do is stop writing code and first solve the problem on paper. Then convert your algorithm to code.
Step one: think!
It is very hard to write a recursive method whose return type is void.
The question is about doing arithmetic, so leave the value as an int rather than convering to a string.
Then there are two facts (for non-negative numbers):
if N is odd then the number of ones is the same as in N/2 plus the one remainder;
if N is even then the number of ones is the same as in N/2.
bitCount of 010101 is bitCount of 010101/2 = 01010 plus 1
bitCount of 010100 is bitCount of 010100/2 = 01010
Rinse and repeat until finished (induction).
Just don't look at the source to Integer.bitCount.
first, reduce the problem to the easiest case ...