Poisson Calc with high factorial - java

i have this piece of Code for the calc:
public static double CalcPoisson(double m, double u, boolean va)
{
double answer = 0;
if(!va)
{
answer = (Math.exp(-u)* Math.pow(u, m)) / (factorial(m));
}
if(va)
{
for(int i = 0; i < m; i++)
{
answer = answer + (Math.exp(-u)* Math.pow(u, i)) / (factorial(i));
}
}
return answer;
And this was my factorial method
public static double factorial (double n)
{
return n == 0 ? 1 : n *factorial(n-1);
}
Problem is: the maximum value to calculate is 170...i need way more (like factorial of 500)
I have written a new Method:
public static BigDecimal factorial2 (double n)
{
BigDecimal fct = BigDecimal.valueOf(1);
for(int i = 1; i<=n; i++)
{
fct = fct.multiply(BigDecimal.valueOf(i));
}
return fct;
How can i use my new factorialmethod in my "CalcPoisson" Method?
Problem is, i cant divide double with BigDecimal...
Thanks for the help :)
For No One:
I have still this Line of Code in one method that uses CalcPoisson, im still bad with BigDecimal, i cant handle it.
The Line:
BigDecimal nenner = CalcPoisson(m, u, false) + (1-p) * CalcPoisson(m, u, true);

for(int i = 0; i < m; i++)
{
answer = answer + (Math.exp(-u)* Math.pow(u, i)) / (factorial(i));
}
Note that this algorithm computes all factorials from 0 through m-1. Much faster and more accurate to factor that out:
long fact = 1;
for(int i = 0; i < m; i++) {
answer = answer + (Math.exp(-u)* Math.pow(u, i)) / fact;
fact *= (i+1);
}
then note that Math.exp(-u) is invariant in the loop, so extract it:
long fact = 1;
double eu = Math.exp(-u);
for(int i = 0; i < m; i++) {
answer = answer + (eu * Math.pow(u, i)) / fact;
fact *= (i+1);
}
And you can also get rid of the repeated calls to Math.pow():
long fact = 1;
double eu = Math.exp(-u);
double term = u;
for(int i = 0; i < m; i++) {
answer = answer + (eu * term) / fact;
fact *= (i+1);
term *= u;
}
Finally, you can also get combine term and fact into a single parameter (left as an exercise for the student).

You could create a new BigDecimal out of the Double
Then you can use the multiplie method of the BigDecimal
fct = fct.multiplie(new BigDecimal(doubleValue));

Your approach is too direct. Such loops are usually written in terms of while (nextTerm < epsilon) , not as a for loop. That is, of course, provided that you can prove that the terms do decrease with i.
The other problem is that while the value of the expression pow(u,i) / factorial(i) may fit in a double, its parts surely do not. You need to compute this in a different way. Of course, as you do, you lose precision, so it becomes even more complicated.
I should better stop. My Math professor promised that he will hunt down and kill any of us who tried to do computational math, and he was a serious gentleman.

You can convert your double to BigDecimal and then you can divide two BigDecimals as following:
BigDecimal answer = BigDecimal.ZERO;
BigDecimal myOwn = new BigDecimal(Double.toString(Math.exp(-u)* Math.pow(u, i)));
answer = answer.add(myOwn.divide(factorial2(i)));
Use BigDecimal to find Factorial as you have done in factorial2().
Finally your method will look like:
public static BigDecimal CalcPoisson(double m, double u, boolean va)
{
BigDecimal answer = BigDecimal.ZERO;
if(!va)
{
BigDecimal myOwn1 = new BigDecimal(Double.toString((Math.exp(-u)* Math.pow(u, m))));
answer = myOwn1.divide(fakultaet(m));
}
if(va)
{
for(int i = 0; i < m; i++)
{
BigDecimal myOwn = new BigDecimal(Double.toString(Math.exp(-u)* Math.pow(u, i)));
answer = answer.add(myOwn.divide(factorial2(i)));
}
}
return answer;
Assuming that you have return type of method fakultaet() is BigDecimal. And if you have return value double for the same, than try:
answer = myOwn1.divide(new BigDecimal(fakultaet(m)));
EDIT
BigDecimal nenner = CalcPoisson(m, u, false).add((BigDecimal.ONE.subtract(new BigDecimal(p))).multiply( CalcPoisson(m, u, true)));

Related

Power to n implementation that produces wrong results for negative exponent

In the following (naive) implementation of a pow(x, n) method, ignoring completely any optimized approach, I find the following problem:
public double pow(double x, int n) {
boolean negative = n < 0;
long power = Math.abs(n);
double ans = 1.0;
for(long i = 0; i < power; i++) {
ans = ans * x;
}
return negative ? 1.0/ans: ans;
}
Here I have made the assumption that for the case of negative exponent I simply calculate the x^n and then return 1/(x^n) since e.g. 2^(-3) = 1/(2^3)
Problem:
The code fails in the following case:
pow(2.00000, -2147483648)
The output is 1.00000 while the expected correct result is 0.00000
If I change the code as follows:
public double pow(double x, int n) {
long power = n;
if(power < 0) {
x = 1 / x;
power = -power;
}
double ans = 1.0;
for(long i = 0; i < power; i++) {
ans = ans * x;
}
return ans;
}
The result is correct!
So what is the difference between doing the approaches? I was expecting them to be equivalent but they are not
Math.abs(n) is still an int, and only afterwards it is assigned to a long, Therefore, the absolute value of -2147483648 was -2147483648 again (this is noted in the documentation of Math.abs(int)). With the negative bound, the loop performed no iterations.
Math.abs((long)n) would work around that issue.

Program for seems to freeze up despite functioning on earlier iterations

I am writing a program to calculate Feigenbaum's constant using the Logistics equation by finding superstable values and then using the ratio of these superstable values to calculate the constant.
I use BigDecimals for almost all of my values so that I can maintain the necessary level of precision during the calculation of the constant.
I am adapting my code from the C++ code on pages 30-35 of the following file: http://webcache.googleusercontent.com/search?q=cache:xabTioRiF0IJ:home.simula.no/~logg/pub/reports/chaos_hw1.ps.gz+&cd=21&hl=en&ct=clnk&gl=us
I doubt what the program does even matters to my question. I run the program, and it seems to be working. The output i get for the first 4 superstable values and the first 2 d's is what is expected, but then after displaying these 4 rows, the program seems to just halt. I don't get an exception, but even after waiting for 30 minutes no more calculations are outputted. I can't figure out what exactly is causing it, because the calculation time should be about the same for each row, yet it obviously is not. Here is my output:
Feigenbaum constant calculation (using superstable points):
j a d
-----------------------------------------------------
1 2.0 N/A
2 3.23606797749979 N/A
4 3.4985616993277016 4.708943013540503
8 3.554640862768825 4.680770998010695
And here is my code:
import java.math.*;
// If there is a stable cycle, the iterates of 1/2 converge to the cycle.
// This was proved by Fatou and Julia.
// (What's special about x = 1/2 is that it is the critical point, the point at which the logistic map's derivative is 0.)
// Source: http://classes.yale.edu/fractals/chaos/Cycles/LogisticCycles/CycleGeneology.html
public class Feigenbaum4
{
public static BigDecimal r[] = new BigDecimal[19];
public static int iter = 0;
public static int iter1 = 20; // Iterations for tolerance level 1
public static int iter2 = 10; // Iterations for tolerance level 2
public static BigDecimal tol1 = new BigDecimal("2E-31"); // Tolerance for convergence level 1
public static BigDecimal tol2 = new BigDecimal("2E-27"); // Tolerance for convergence level 2
public static BigDecimal step = new BigDecimal("0.01"); // step when looking for second superstable a
public static BigDecimal x0 = new BigDecimal(".5");
public static BigDecimal aZero = new BigDecimal("2.0");
public static void main(String [] args)
{
System.out.println("Feigenbaum constant calculation (using superstable points):");
System.out.println("j\t\ta\t\t\td");
System.out.println("-----------------------------------------------------");
int n = 20;
if (FindFirstTwo())
{
FindRoots(n);
}
}
public static BigDecimal F(BigDecimal a, BigDecimal x)
{
BigDecimal temp = new BigDecimal("1");
temp = temp.subtract(x);
BigDecimal ans = (a.multiply(x.multiply(temp)));
return ans;
}
public static BigDecimal Dfdx(BigDecimal a, BigDecimal x)
{
BigDecimal ans = (a.subtract(x.multiply(a.multiply(new BigDecimal("2")))));
return ans;
}
public static BigDecimal Dfda(BigDecimal x)
{
BigDecimal temp = new BigDecimal("1");
temp = temp.subtract(x);
BigDecimal ans = (x.multiply(temp));
return ans;
}
public static BigDecimal NewtonStep(BigDecimal a, BigDecimal x, int n)
{
// This function returns the Newton step for finding the root, a,
// of fn(x,a) - x = 0 for a fixed x = X
BigDecimal fval = F(a, x);
BigDecimal dval = Dfda(x);
for (int i = 1; i < n; i++)
{
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
fval = F(a, fval);
}
BigDecimal ans = fval.subtract(x);
ans = ans.divide(dval, MathContext.DECIMAL64);
ans = ans.negate();
return ans;
}
public static BigDecimal Root(BigDecimal a0, int n)
{
// Find the root a of fn(x,a) - x = 0 for fixed x = X
// with Newton’s method. The initial guess is a0.
//
// On return iter is the number of iterations if
// the root was found. If not, iter is -1.
BigDecimal a = a0;
BigDecimal a_old = a0;
BigDecimal ans;
// First iter1 iterations with a stricter criterion,
// tol1 < tol2
for (iter = 0; iter < iter1; iter++)
{
a = a.add(NewtonStep(a, x0, n));
// check for convergence
BigDecimal temp = a.subtract(a_old);
temp = temp.divide(a_old, MathContext.DECIMAL64);
ans = temp.abs();
if (ans.compareTo(tol1) < 0)
{
return a;
}
a_old = a;
}
// If this doesn't work, do another iter2 iterations
// with the larger tolerance tol2
for (; iter < (iter1 + iter2); iter++)
{
a = a.add(NewtonStep(a, x0, n));
// check for convergence
BigDecimal temp = a.subtract(a_old);
temp = temp.divide(a_old, MathContext.DECIMAL64);
ans = temp.abs();
if (ans.compareTo(tol2) < 0)
{
return a;
}
a_old = a;
}
BigDecimal temp2 = a.subtract(a_old);
temp2 = temp2.divide(a_old, MathContext.DECIMAL64);
ans = temp2.abs();
// If not out at this point, iterations did not converge
System.out.println("Error: Iterations did not converge,");
System.out.println("residual = " + ans.toString());
iter = -1;
return a;
}
public static boolean FindFirstTwo()
{
BigDecimal guess = aZero;
BigDecimal r0;
BigDecimal r1;
while (true)
{
r0 = Root(guess, 1);
r1 = Root(guess, 2);
if (iter == -1)
{
System.out.println("Error: Unable to find first two superstable orbits");
return false;
}
BigDecimal temp = r0.add(tol1.multiply(new BigDecimal ("2")));
if (temp.compareTo(r1) < 0)
{
System.out.println("1\t\t" + r0.doubleValue() + "\t\t\tN/A");
System.out.println("2\t" + r1.doubleValue() + "\t\tN/A");
r[0] = r0;
r[1] = r1;
return true;
}
guess = guess.add(step);
}
}
public static void FindRoots(int n)
{
int n1 = 4;
BigDecimal delta = new BigDecimal(4.0);
BigDecimal guess;
for (int i = 2; i < n; i++)
{
// Computation
BigDecimal temp = (r[i-1].subtract(r[i-2])).divide(delta, MathContext.DECIMAL64);
guess = r[i-1].add(temp);
r[i] = Root(guess, n1);
BigDecimal temp2 = r[i-1].subtract(r[i-2]);
BigDecimal temp3 = r[i].subtract(r[i-1]);
delta = temp2.divide(temp3, MathContext.DECIMAL64);
// Output
System.out.println(n1 + "\t" + r[i].doubleValue() + "\t" + delta.doubleValue());
// Step to next superstable orbit
n1 = n1 * 2;
}
}
}
EDIT:
Phil Steitz's Answer essentially solved my problem. I looked at some thread dumps, and after doing a bit of research to try and understand them, and compiling my program with debugging info, I was able to find that the main thread was stalling at the line:
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
as Phil Steit's said, by using
MathContext.DECIMAL128
in not only this line:
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
but also in my multiplication operations in the methods F, Dfda, and Dfdx, I was able to get my code to work properly.
I used DECIMAL128 because the smaller precision made the calculation non-functional, because I compare them to such low numbers for the tolerance check.
I think that what is going on here is that when n is larger than about 10, your NewtonStep method becomes very slow because none of your multiply invocations limit the scale by providing a MathContext. When no MathContext is provided, the result of a multiply gets the sum of the scales of the multiplicands. With the code above, the scales of dval and fval inside the for loop in NewtonStep get very large for large n, resulting in very slow multiplications in this method and the methods that it calls. Try specifying MathContext.DECIMAL64 (or something else) in the multiply activations as you do for the divides.

Double to fraction in Java

So what I'm trying to do is convert double to rational number. I check how many digits there is after decimal point and I want to save the number 123.456 as 123456 / 1000, for example.
public Rational(double d){
String s = String.valueOf(d);
int digitsDec = s.length() - 1 - s.indexOf('.');
for(int i = 0; i < digitsDec; i++){
d *= 10;
}
System.out.println((int)d); //checking purposes
}
However, for the number 123.456 I get a round off error and the result is 123455. I guess it'd be possible to fix this with BigDecimal but I can't get it to work. Also, having calculated what rational number it would be, I would like to call another constructor with parameters (int numerator, int denominator) but I can't obviously call the constructor in the line where println is now. How should I do this?
For the first part of the question, Java is storing .6 as .5999999 (repeating). See this output:
(after first multiply): d=1234.56
(after second multiply): d=12345.599999999999
(after third multiply): d=123455.99999999999
One fix is to use d = Math.round(d) immediately after your loop finishes.
public class Rational {
private int num, denom;
public Rational(double d) {
String s = String.valueOf(d);
int digitsDec = s.length() - 1 - s.indexOf('.');
int denom = 1;
for(int i = 0; i < digitsDec; i++){
d *= 10;
denom *= 10;
}
int num = (int) Math.round(d);
this.num = num; this.denom = denom;
}
public Rational(int num, int denom) {
this.num = num; this.denom = denom;
}
public String toString() {
return String.valueOf(num) + "/" + String.valueOf(denom);
}
public static void main(String[] args) {
System.out.println(new Rational(123.456));
}
}
It works - try it.
For the second part of your question...
In order to call the second constructor from the first, you can use the "this" keyword
this(num, denom)
But it has to be the very first line in the constructor... which doesn't make sense here (we have to do some calculations first). So I wouldn't bother trying to do that.
This code may be overkill for you, but it deals with the rounding error that you're experiencing, and it also takes care of repeating decimals (4.99999999999999 turns into 5, and 0.33333333333333333333 turns into 1/3).
public static Rational toRational(double number){
return toRational(number, 8);
}
public static Rational toRational(double number, int largestRightOfDecimal){
long sign = 1;
if(number < 0){
number = -number;
sign = -1;
}
final long SECOND_MULTIPLIER_MAX = (long)Math.pow(10, largestRightOfDecimal - 1);
final long FIRST_MULTIPLIER_MAX = SECOND_MULTIPLIER_MAX * 10L;
final double ERROR = Math.pow(10, -largestRightOfDecimal - 1);
long firstMultiplier = 1;
long secondMultiplier = 1;
boolean notIntOrIrrational = false;
long truncatedNumber = (long)number;
Rational rationalNumber = new Rational((long)(sign * number * FIRST_MULTIPLIER_MAX), FIRST_MULTIPLIER_MAX);
double error = number - truncatedNumber;
while( (error >= ERROR) && (firstMultiplier <= FIRST_MULTIPLIER_MAX)){
secondMultiplier = 1;
firstMultiplier *= 10;
while( (secondMultiplier <= SECOND_MULTIPLIER_MAX) && (secondMultiplier < firstMultiplier) ){
double difference = (number * firstMultiplier) - (number * secondMultiplier);
truncatedNumber = (long)difference;
error = difference - truncatedNumber;
if(error < ERROR){
notIntOrIrrational = true;
break;
}
secondMultiplier *= 10;
}
}
if(notIntOrIrrational){
rationalNumber = new Rational(sign * truncatedNumber, firstMultiplier - secondMultiplier);
}
return rationalNumber;
}
This provides the following results (results from test cases are shown as comments):
Rational.toRational(110.0/3.0); // 110/3
Rational.toRational(11.0/1000.0); // 11/1000
Rational.toRational(17357.0/33300.0); // 17357/33300
Rational.toRational(215.0/21.0); // 215/21
Rational.toRational(0.123123123123123123123123); // 41/333
Rational.toRational(145731.0/27100.0); // 145731/27100
Rational.toRational(Math.PI); // 62831853/20000000
Rational.toRational(62.0/63.0); // 62/63
Rational.toRational(24.0/25.0); // 24/25
Rational.toRational(-24.0/25.0); //-24/25
Rational.toRational(-0.25333333333333333333333); // -19/75
Rational.toRational(-4.9999999999999999999999); // -5
Rational.toRational(4.9999999999999999999999); // 5
Rational.toRational(123.456); // 15432/125
It's not elegant, however, I believe this does what you're asking.
double a = 123.456;
String aString = Double.toString(a);
String[] fraction = aString.split("\\.");
int denominator = (int)Math.pow(10, fraction[1].length());
int numerator = Integer.parseInt(fraction[0] + "" + fraction[1]);
System.out.println(numerator + "/" + denominator);
Here, d=123.456 then num=123456, j=1000.
/**
* This method calculates a rational number from a double.
* The denominator will always be a multiple of 10.
*
* #param d the double to calculate the fraction from.
* #return the result as Pair of <numerator , denominator>.
*/
private static Pair<Integer,Integer> calculateRational(double d){
int j=1, num;
do{
j=j*10;
}while((d *j)%10!=0);
j=j/10;
num=(int)(d*j);
return new Pair<>(num,j);
}
Here're some tests:
#Test
public void testCalculateRational() {
Assert.assertEquals(new Pair<>(124567, 1000), calculateRational(124.567));
Assert.assertEquals(new Pair<>(12456, 100), calculateRational(124.56));
Assert.assertEquals(new Pair<>(56, 100), calculateRational(0.56));
}
Try
for(int i = 0; i <= digitsDec; i++){
}

How to write 1+1/2+1/3....+1/4999+1/5000 in java?

How to write 1+1/2+1/3....+1/4999+1/5000 in java?
I have tried this but didnt work.
public class Harmonic{
public static void main(String[] args){
double sum = 0;
for(int i=1; i<=5000; i++){
sum+=1/i;
}
System.out.println(sum);
}
}
Adding numbers from smallest to largest will have a lower rounding error. If you compare the result with higher precision, you can see smaller to larger is closer.
double sum = 0;
for (int i = 1; i <= 5000; i++) {
sum += 1.0 / i;
}
System.out.println("From largest to smallest " + sum);
double sum2 = 0;
for (int i = 5000; i >= 1; i--) {
sum2 += 1.0 / i;
}
System.out.println("From smallest to largest " + sum2);
BigDecimal sum3 = BigDecimal.ZERO;
for (int i = 5000; i >= 1; i--) {
sum3 = sum3.add(BigDecimal.ONE.divide(BigDecimal.valueOf(i), 30, BigDecimal.ROUND_HALF_UP));
}
System.out.println("BigDecimal " + sum3);
prints
From largest to smallest 9.094508852984404
From smallest to largest 9.09450885298443
BigDecimal 9.094508852984436967261245533401
1 is an int constant, so 1 / (any int bigger than 1) is 0. You need to specify that you want a floating point division, by using 1.0 (float):
sum+=1.0/i;
^
That's a homework, then I just help you with a tip: be careful of variable types. 1/10 is equal to 0 if we consider it as an integer.
Try this instead:
sum += 1.0 / i;
How about:
public class Harmonic{
public static void main(String[] args){
double sum = 0;
for(int i=1; i<=5000; i++){
sum+=1.0/(double)i;
}
System.out.println(sum);
}
}
After the first iteration 1/i will always be 0 since it's done in integer arithmetic. Therefore you're final answer will just be 1. Change it to 1.0/i to get double arithmetic, and keep in mind that when you're loop finishes you may have a fair amount of error due to precision loss while using doubles. You can try it out and see how accurate it is though.
because i is an int so the division will be truncated... try putting sum+ = 1/(double)i
java-8 solution for calculating Harmonic sum:
public static double harmonicSum(int n) {
return IntStream.rangeClosed(1, n)
.mapToDouble(i -> (double) 1 / i)
.sum();
}

Counting trailing zeros of numbers resulted from factorial

I'm trying to count trailing zeros of numbers that are resulted from factorials (meaning that the numbers get quite large). Following code takes a number, compute the factorial of the number, and count the trailing zeros. However, when the number is about as large as 25!, numZeros don't work.
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
double fact;
int answer;
try {
int number = Integer.parseInt(br.readLine());
fact = factorial(number);
answer = numZeros(fact);
}
catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static double factorial (int num) {
double total = 1;
for (int i = 1; i <= num; i++) {
total *= i;
}
return total;
}
public static int numZeros (double num) {
int count = 0;
int last = 0;
while (last == 0) {
last = (int) (num % 10);
num = num / 10;
count++;
}
return count-1;
}
I am not worrying about the efficiency of this code, and I know that there are multiple ways to make the efficiency of this code BETTER. What I'm trying to figure out is why the counting trailing zeros of numbers that are greater than 25! is not working.
Any ideas?
Your task is not to compute the factorial but the number of zeroes. A good solution uses the formula from http://en.wikipedia.org/wiki/Trailing_zeros (which you can try to prove)
def zeroes(n):
i = 1
result = 0
while n >= i:
i *= 5
result += n/i # (taking floor, just like Python or Java does)
return result
Hope you can translate this to Java. This simply computes [n / 5] + [n / 25] + [n / 125] + [n / 625] + ... and stops when the divisor gets larger than n.
DON'T use BigIntegers. This is a bozosort. Such solutions require seconds of time for large numbers.
You only really need to know how many 2s and 5s there are in the product. If you're counting trailing zeroes, then you're actually counting "How many times does ten divide this number?". if you represent n! as q*(2^a)*(5^b) where q is not divisible by 2 or 5. Then just taking the minimum of a and b in the second expression will give you how many times 10 divides the number. Actually doing the multiplication is overkill.
Edit: Counting the twos is also overkill, so you only really need the fives.
And for some python, I think this should work:
def countFives(n):
fives = 0
m = 5
while m <= n:
fives = fives + (n/m)
m = m*5
return fives
The double type has limited precision, so if the numbers you are working with get too big the double will be only an approximation. To work around this you can use something like BigInteger to make it work for arbitrarily large integers.
You can use a DecimalFormat to format big numbers. If you format your number this way you get the number in scientific notation then every number will be like 1.4567E7 this will make your work much easier. Because the number after the E - the number of characters behind the . are the number of trailing zeros I think.
I don't know if this is the exact pattern needed. You can see how to form the patterns here
DecimalFormat formater = new DecimalFormat("0.###E0");
My 2 cents: avoid to work with double since they are error-prone. A better datatype in this case is BigInteger, and here there is a small method that will help you:
public class CountTrailingZeroes {
public int countTrailingZeroes(double number) {
return countTrailingZeroes(String.format("%.0f", number));
}
public int countTrailingZeroes(String number) {
int c = 0;
int i = number.length() - 1;
while (number.charAt(i) == '0') {
i--;
c++;
}
return c;
}
#Test
public void $128() {
assertEquals(0, countTrailingZeroes("128"));
}
#Test
public void $120() {
assertEquals(1, countTrailingZeroes("120"));
}
#Test
public void $1200() {
assertEquals(2, countTrailingZeroes("1200"));
}
#Test
public void $12000() {
assertEquals(3, countTrailingZeroes("12000"));
}
#Test
public void $120000() {
assertEquals(4, countTrailingZeroes("120000"));
}
#Test
public void $102350000() {
assertEquals(4, countTrailingZeroes("102350000"));
}
#Test
public void $1023500000() {
assertEquals(5, countTrailingZeroes(1023500000.0));
}
}
This is how I made it, but with bigger > 25 factorial the long capacity is not enough and should be used the class Biginteger, with witch I am not familiar yet:)
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
System.out.print("Please enter a number : ");
long number = in.nextLong();
long numFactorial = 1;
for(long i = 1; i <= number; i++) {
numFactorial *= i;
}
long result = 0;
int divider = 5;
for( divider =5; (numFactorial % divider) == 0; divider*=5) {
result += 1;
}
System.out.println("Factorial of n is: " + numFactorial);
System.out.println("The number contains " + result + " zeroes at its end.");
in.close();
}
}
The best with logarithmic time complexity is the following:
public int trailingZeroes(int n) {
if (n < 0)
return -1;
int count = 0;
for (long i = 5; n / i >= 1; i *= 5) {
count += n / i;
}
return count;
}
shamelessly copied from http://www.programcreek.com/2014/04/leetcode-factorial-trailing-zeroes-java/
I had the same issue to solve in Javascript, and I solved it like:
var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
count++;
}
console.log(count) // console shows 4
This solution gives you the number of trailing zeros.
var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
count++;
}
console.log(count)
Java's doubles max out at a bit over 9 * 10 ^ 18 where as 25! is 1.5 * 10 ^ 25. If you want to be able to have factorials that high you might want to use BigInteger (similar to BigDecimal but doesn't do decimals).
I wrote this up real quick, I think it solves your problem accurately. I used the BigInteger class to avoid that cast from double to integer, which could be causing you problems. I tested it on several large numbers over 25, such as 101, which accurately returned 24 zeros.
The idea behind the method is that if you take 25! then the first calculation is 25 * 24 = 600, so you can knock two zeros off immediately and then do 6 * 23 = 138. So it calculates the factorial removing zeros as it goes.
public static int count(int number) {
final BigInteger zero = new BigInteger("0");
final BigInteger ten = new BigInteger("10");
int zeroCount = 0;
BigInteger mult = new BigInteger("1");
while (number > 0) {
mult = mult.multiply(new BigInteger(Integer.toString(number)));
while (mult.mod(ten).compareTo(zero) == 0){
mult = mult.divide(ten);
zeroCount += 1;
}
number -= 1;
}
return zeroCount;
}
Since you said you don't care about run time at all (not that my first was particularly efficient, just slightly more so) this one just does the factorial and then counts the zeros, so it's cenceptually simpler:
public static BigInteger factorial(int number) {
BigInteger ans = new BigInteger("1");
while (number > 0) {
ans = ans.multiply(new BigInteger(Integer.toString(number)));
number -= 1;
}
return ans;
}
public static int countZeros(int number) {
final BigInteger zero = new BigInteger("0");
final BigInteger ten = new BigInteger("10");
BigInteger fact = factorial(number);
int zeroCount = 0;
while (fact.mod(ten).compareTo(zero) == 0){
fact = fact.divide(ten);
zeroCount += 1;
}
}

Categories