My for loop increment seems to be wrong - java

I am doing a question for college on cryptography. Part of my program is that I want to get the power x such that (2744^x) % 24852977 = 8414508. I have a loop that increases a double by 0.001. My question is this: instead of my loop increasing by 0.001 each time it shows a number a lot longer in decimal places. Is this to do with the long MIN/MAX value and if so how would i be able to fix this, or can anyone explain were I'm going wrong? Here is a sample of my increment. How do get the cut off point of 4 decimal places.
10.276999999989387
10.277099999989387
10.277199999989387
10.277299999989387
10.277399999989386
10.277499999989386
10.277599999989386
10.277699999989386
10.277799999989385
import java.lang.*;
public class crypt {
public static void main(String args[])
{
long p =24852977;//variables
long g = 2744;
long sum = 8414508;
long c1 = 15268076;
long c2 = 743675;
for(double i=0; i<=p; i=i+0.0001)//loop for increasing the power in next part of the program
{
long num=(long)(Math.pow((long)g, i));//number = g to the power of i
System.out.println(i);// just to check
if(num % p == sum)//my equation
{
System.out.println(i);//print the power that satisfy's this
}
}
}
}

Remember that the internal representation of numbers is binary. So, there is not necessarily an exact binary representation for every decimal number. That is, there is no exact representation of your 0.0001 increment and a rounding error is expected.

Related

Java double to int convertion changes sign of result

I tried to calculate a series of the N first fibonacci numbers using Binets Formula.
Every result i get is correct until F47 where the result is NEGATIVE.
This is my result : -1323752223
And heres the expected result : 2971215073
I really think the problem occures during the double to int conversion
Source Code:
import java.lang.Math;
class fibonacci{
public static int NthFibonacci(int n){
double fi = 1.61803398875;
int fb = (int)Math.round((Math.pow(fi,n) - Math.pow(1-fi,n))/Math.sqrt(5));
return fb;
}
public static void FibonacciSeries(Integer n){
for(int i = 0; i < n; i++){
System.out.println(NthFibonacci(i) + " ");
}
}
public static void main(String[] args) {
FibonacciSeries(50);
}
}
The real explanation for the behavior of the version in your question giving a negative number is a bit subtle.
At F47, this expression
(Math.pow(fi, n) - Math.pow(1 - fi, n)) / Math.sqrt(5)
will give you 2.971215073009069E9 ... which is close to the desired 2971215073.
The problem arises when you call Math.round(2.971215073009069E9). This returns a long - 2971215073L. But then you cast the result of the round call to an int, and it all goes pear-shaped.
Casting a long to an int will just lop off the top 32 bits ... and that results in a meaningless number.
If we modify fibonacci to return a long instead of an int, we get correct results up to F55. F56 and F57 are off by 1. F58 is off by 2.
What is happening now is that we are running into the problem that double (64-bit IEEE floating point) has only about 13.5 decimal digits of precision. The rounding error incurred in the computation of the intermediate floating point value for F56 larger that 0.5 ... so the rounded value is then incorrect.
The computed fibonacci numbers continue to get increasingly inaccurate until you get to F93, where the (modified) fibonacci method returns Long.MAX_VALUE.
To get correct values for very large Fibonacci numbers:
we need to use BigInteger to represent the numbers,
we need to do the computations using BigDecimal with sufficient precision, and (maybe)
we need to use a more accurate value for phi.
Or we need to use the recurrence relationship to compute the numbers.
The 2 take-aways from all of this are:
casting a long to an int is a lossy conversion, and
floating point arithmetic is inexact and ... tricky.
I think that the problem does not have something to do with the double conversion.
int can store numbers that can be represented by 32 bits. This means the highest number integer can represents is 2.147.483.647.
The F47 is breaking this limit and results in an bit-overflow, so it starts at -2.147.483.68 and adds the rest of your 2971215073 - 2147483647 to it. -1323752223 is the outcome.
Use a long (64bit) instead of an int and you should be good :)
2971215073 is too big to be represented as an int at all. The maximum value of an int -- Integer.MAX_VALUE -- is 2^31 - 1, or 2147483647.
Ok so i found a decent fix.
I used a Geometrical version of Binets rule which you can find here : Binets Geometrical Rule
I also used long instead of int so now I can accurately calculate up to F70. F71 is wrong by a digit and after that it just builds up.
New Source Code :
import java.lang.Math;
class fibonacci{
public static long NthFibonacci(int n){
double a = (1/Math.sqrt(5))*Math.pow(2, n);
double radians1 = Math.toRadians(36.0);
double radians2 = Math.toRadians(108.0);
double b = Math.pow(Math.cos(radians1), n) - Math.pow(Math.cos(radians2), n);
long fb = (long) Math.round(a*b);
return fb;
}
public static void FibonacciSeries(int n){
for(int i = 0; i < n; i++){
System.out.println( i + " : " + NthFibonacci(i));
}
}
public static void main(String[] args) {
FibonacciSeries(100);
}
}

Finding the max product of consecutive digits (Project Euler #8)

Project Euler problem 8 involves finding the largest product of 13 consecutive digits in a 1000-digit number. I've tried to solve this problem with the code below, but the results I am getting are too small by a factor of about 10. What have I done wrong?
import java.util.Scanner;
import java.util.*;
public class eight {
public static void main(String[] args) {
String number="7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
String input = "782";
int value = 782;
List<Integer> x = new ArrayList<Integer>();
for (char ch : number.toCharArray()){
int element_add=Character.getNumericValue(ch);
x.add(element_add);
}
int check_count=0;
int multiply_value=0;
int multiply_value_max=0;
while(check_count<986){
multiply_value=(x.get(check_count))*(x.get(check_count+1))*(x.get(check_count+2))*(x.get(check_count+3))*(x.get(check_count+4))*(x.get(check_count+5))*(x.get(check_count+6))*(x.get(check_count+7))*(x.get(check_count+8))*(x.get(check_count+9))*(x.get(check_count+10))*(x.get(check_count+11))*(x.get(check_count+12));
if(multiply_value>multiply_value_max){
multiply_value_max=multiply_value;
}
check_count++;
}
System.out.println(multiply_value_max);
}
}
The problem you have is that the upper bound for the answer can be greater than maximum value of int. Therefore, you need to use the BigInteger class, or at the very least long, to store the result. To ensure that the operations are carried out with sufficient precision, you want to store the individual digits in the same precision or convert them to the precision as you multiply them.
You can also save yourself some typing and boilerplate errors by handling the consecutive multiplication with a for loop.

Project euler 10 help. Whats wrong with this code? the sum flips to negative [duplicate]

This question already has answers here:
How does Java handle integer underflows and overflows and how would you check for it?
(12 answers)
Closed 8 years ago.
// finding sum of all primes under 2 million
public class lll {
public static void main(String[] args) {
int a = 2;
int b = 0;
int c = 0;
while (a < 2000000) {
int i = 1;
for (i = 1; i * i <= a; i++) {
if (a % i == 0)
//if factor is found of number a b goes up 1
{
b++;
}
}
// all primes have only one factor <= sqrt (1)
if (b == 1)
// if b =1 , a is prime so c+=a
{
c += a;
}
//reset b and add one to a to move on
b = 0;
a++;
// for error checking see description
System.out.println(c);
}
System.out.println(c);
}
}
Im trying to make a code to find the sum of all primes under 2 million, heres what i have it gives 1179908154, but this is not right, c is supposed to be the sum. I tried getting c after every check of number being prime and it shows that during the running of this code it lips from positive to negative and then back again. it makes no sense a starts at 1, a goes up c starts at 0, it goes up by a so how is c getting negative (a is never negative), please help me, I have managed to used this method of prime checking to correctly get the 10001st prime, it worked then.
A 32 bit integer can only hold numbers below about 2 billion. If you try to add more to that number (accessible by Integer.MAX_VALUE), you will end up "flipping" to negative numbers. Try out the following code:
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MAX_VALUE + 1);
System.out.println(Integer.MIN_VALUE);
So your problem is that integers aren't big enough! How can you solve this? The simplest way is to use a long instead of an int. Hypothetically, what if a long isn't even big enough? Then you can use a class like BigInteger, which isn't constrained to a fixed number of bits, and can grow as necessary.
Well, you declared c as an int which in java has a max value of 2,147,483,647 . The sum of all primes less than 1 million is 37,550,402,023, so Im thinking you are surpassing the data storage for int which is why its flipping negative on you.
My guess is that it has something to do with memory. In java the maximum number an integer can hold is 2147483647. So if the sum of primes goes over this number, it will loop back to -2147483648 and continue counting. Try making your variable c a long instead.

BigInteger Sqrt Function isn't converging

I am currently writing a function to find the square root of a given BigInteger. The current number in my test file is 250074134890485729738. The program however always stalls while finding the sqrt at 15813732488, which squared is 250074135202026670144. I have copied this
code from another StackOverflow problem, and it ceases converging at the same number. It uses Newtons Method, while I'm using the Babylonian/Heron's Method.
Their Code:
public static BigInteger sqrtN(BigInteger in) {
final BigInteger TWO = BigInteger.valueOf(2);
int c;
// Significantly speed-up algorithm by proper select of initial approximation
// As square root has 2 times less digits as original value
// we can start with 2^(length of N1 / 2)
BigInteger n0 = TWO.pow(in.bitLength() / 2);
// Value of approximate value on previous step
BigInteger np = in;
do {
// next approximation step: n0 = (n0 + in/n0) / 2
n0 = n0.add(in.divide(n0)).divide(TWO);
// compare current approximation with previous step
c = np.compareTo(n0);
// save value as previous approximation
np = n0;
// finish when previous step is equal to current
} while (c != 0);
return n0;}
My Code:
static BigInteger number;
static BigInteger sqrt;
public static void main(String[] args) throws Exception {
number = new BigInteger(getFile());
System.out.println("Factoring: \n\n" + number);
sqrt = sqrt();
System.out.println("The root is: " + sqrt.toString());
System.out.println("Test, should equal nearest square at or above original number: " + sqrt.multiply(sqrt).toString() + "\nOriginal number: " + number.toString());
}
public static BigInteger sqrt() {
BigInteger guess = number.divide(new BigInteger("500"));
BigInteger TWO = new BigInteger("2");
BigInteger HUNDRED = new BigInteger("100");
boolean go = true;
while (number.subtract((guess.multiply(guess))).abs().compareTo(HUNDRED) == 1 && go){
BigInteger numOne = guess.divide(TWO);
BigInteger numTwo = number.divide(guess.multiply(TWO));
guess = numOne.add(numTwo);
if (numOne.equals(numTwo))
go = false;
System.out.println(guess.toString());
}
return guess.add(BigInteger.ONE);
My Output:
Factoring:
250074134890485729738
250074134890485979
125037067445243488
62518533722622743
31259266861313370
15629633430660684
7814816715338341
3907408357685169
1953704178874583
976852089501290
488426044878644
244213022695321
122106511859659
61053256953828
30526630524913
15263319358455
7631667871224
3815850319588
1907957927606
954044498302
477153309146
238838702566
119942872245
61013907968
32556274730
20118781556
16274333124
15820250501
15813733820
15813732478
15813732478
The root is: 15813732479
Test, should equal nearest square at or above original number: 250074134917379485441
Original number: 250074134890485729738
A couple notes:
I had a couple of ideas while writing this and I tried them. If something doesn't match up, that's my fault. I did check, but I'm not perfect.
While I appreciate people being generous enough to point me towards a different piece of pre-written code/post their own, this (while not school work) is a learning experience for me. PLEASE DO post how this code could be fixed, PLEASE DO NOT just post a different piece of code that does the same.
ANSWER: This actually does work as is, the original input is simply not a perfect square. Therefore, this works perfectly for my purposes. Thanks to all who wasted their time due to my incompetence. I have changed the code to return a value equivalent to (if Math.sqrt/ceil worked on BigInts):
sqrt = Math.Ceil(Math.Sqrt(A_RANDOM_BIGINTEGER_HERE));
I have also removed unnecessary variables, and updated the output to match. Both these methods work fine, although the first one requires some code to catch the non-convergence cycle, in case any future visitors to this question wish to use them.
15813732478 is the square root of 250074134890485729738, at least the integral part of it. The real square root is 15813732478.149670840219509075711, according to calc.
There are two problems:
You are looping 100 times instead of stopping at convergence.
Your assumption that sqrt(N)*sqrt(N) = N is fallacious, because you're only computing the integral part, so there will be an error proportional to N.
You have in your while loop in your sqrt() function a compareTo(100) which (I suspect) is always returning 1 ie the absolute value of number minus the guess squared is always greater than 100.
Which after testing I see that it is, add this at the end of your loop and you'll see that the difference once you reach the root is still very large = 4733709254
At this point numOne and numTwo become the same value so guess is always the same for each subsequent iteration also.
System.out.println("Squaring:" + guess.multiply(guess).toString() +
"; Substracting: " + number.subtract((guess.multiply(guess))).toString());
You also have c < 100 so if that comparison is always true then it will always print 100 lines.

Dealing with overflow in Java without using BigInteger

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.

Categories