Double to fraction in Java - 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++){
}

Related

Method simplify(Fraction f) does not work

I have a class Calculator which aggregates instances of a class Fraction as its attributes.
Class Fraction has attributes num for numerator and denom for denominator.
Here is an abstract of the code with 'multiply' and 'simplify' (to get a fraction in its lowest terms) methods.
public class Calculator {
private Fraction f1 = new Fraction(4, 9);
private Fraction f2 = new Fraction(3, 8);
public void multiply() throws Exception {
int num = f1.getNum() * f2.getNum();
int denom = f1.getDenom() * f2.getDenom();
Fraction f = new Fraction(num, denom);
simplify(f);
System.out.print(f);
}
private void simplify(Fraction f) throws Exception {
int num = f.getNum();
int denom = f.getDenom();
for (int i = num; i > 0; i--) {
if ((num % i == 0) && (denom % i == 0)) {
num = num / i;
denom = denom / i;
break;
}
}
}
However, I get 12/72 as a result of multiplication while I should get 1/6.
How can I change the code so that 'simplify' method works when invoked in 'multiply'?
As Edwin commented you want algorithm for greatest common divisor. However to answer your question, you got unexpected result because the newly computed variables num and denom at the line with num = num / i are not stored back into Fraction f.
Either (worse option) call f.setNum(num); f.setDenom(denom) or (better) change Fraction to immutable class and return new Fraction from simplify method.

Trying Junit for the first time and failing

I'm trying to use Junit for the first time but I'm facing some unexpected failure.
Here is the failure message:
org.opentest4j.AssertionFailedError: expected: <2> but was: <19>.
It would be great if someone will be able to help me understand where is my error.
I spend more than 30 minutes in trying to understand the reason behind it and I can't. I guess I need to do a minor change somewhere.
public class Fraction {
private int numerator;
private int denominator;
public int getNumerator() {
return numerator;
}
public int getDenomonator() {
return denominator;
}
public Fraction(int n, int d) {
numerator = n;
denominator = d;
}
/**
* This method is adding other fraction
* to our current(this) fraction
* #param otherFraction
*/
public void add(Fraction otherFraction) {
int a = numerator;
int b = denominator;
int c = otherFraction.getNumerator();
int d = otherFraction.getDenomonator();
numerator = a * d + b * c;
denominator = b * d;
int min = denominator;
if (numerator < denominator) {
min = numerator;
}
int commonDiv = 1;
for (int i = 1; i <= min; i++) {
if ((numerator % i == 0) && (denominator % 1 == 0)) {
commonDiv = i;
}
}
numerator = numerator / commonDiv;
denominator = denominator / commonDiv;
if (numerator == 0) denominator = 1;
}
}
Test:
class FreactionTest {
#Test
void test() {
Fraction f1 = new Fraction(3,4);
Fraction f2 = new Fraction(5,6);
f1.add(f2);
assertEquals(f1.getNumerator(),19);
assertEquals(f1.getDenomonator(),12);
}
#Test
void testAddNegative() {
Fraction f1 = new Fraction(3,4);
Fraction f2 = new Fraction(-3,4);
f1.add(f2);
assertEquals(f1.getNumerator(),0);
assertEquals(f1.getDenomonator(),1);
}
}
I expected the code to run successfully.
It looks like you have your expected/actual backwards in the call to assertEquals(). According to the docs here, the first argument is the expected value, and the second argument is the actual value. So you need to switch your arguments, since right now you're hard-coding the actual result to be 19. The call you're trying to test should be the second argument, and the value you expect to be returned should be the first argument. You're doing it in all your other assertEquals() calls also, so be sure to change those as well.

java.lang.StringIndexOutOfBoundsException on repeating decimal to fraction calculator

I'm new to java and I'm trying to code a method that takes a repeating decimal and turns it into a fraction. It takes input like (double decimal without repeating, int number of trailing digits to repeat) i.e. (0.3,1) would be 0.3333.... and (1.583,2) would be 1.5838383....
I am getting this error and I can't seem to find out what the problem is. The current input is (10.3,1)
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1967)
at Fraction.<init>(Fraction.java:44)
at Main.main(Main.java:12)
exited with non-zero status
Heres my code:
public Fraction(double t, int repeating)
{
double decRight = t, decLeft = t;
String rStr = "0000000000000000000" + String.valueOf(decRight);
String lStr = "0000000000000000000" + String.valueOf(decLeft);
int count1 = 0, count2 = 0, rDecIndex = rStr.indexOf("."), lDecIndex = lStr.indexOf(".");
while(!lStr.substring(lDecIndex - repeating,lDecIndex).replace("\\.","").equals(lStr)) //this is line 44, the problem area
{
decLeft *= 10;
count1++;
lStr = "0000000000000000000" + String.valueOf(decLeft);
lDecIndex = lStr.indexOf(".");
}
while(!rStr.substring(rDecIndex,repeating).replace("\\.","").equals(rStr))
{
decRight*= 10;
count2++;
rStr = "0000000000000000000" + String.valueOf(decRight);
rDecIndex = rStr.indexOf(".");
}
top = (int)(decLeft - decRight);
bot = (int)(Math.pow(10,count1) - Math.pow(10,count2));
reduce();
}
The error is in the substring.
Based on the comment, you want an integer with the repeating decimal in it and an integer with what is before the repeating part.
I think you've gone about this the hard way rather than just using substring to get the parts of the string that you want.
/**
* Code By Loren CC-BY
*/
public class test
{
public static void fraction(String t, int repeating)
{
int bot = 0;
for (int i = 0; i < repeating; i++) {
bot *= 10;
bot += 9;
}
String dString = t;
// Get the repeating part of the string as an int
int repeat = Integer.valueOf(dString.substring(dString.length()-repeating));
// Get the string from in front of the repeating number
String front = dString.substring(0, dString.length()-repeating);
// Convert it to a double
double before = Double.valueOf(front);
// Debugging information
System.out.println("Before: "+ front+" " +before+" "+dString.substring(dString.length()-repeating));
// Turn the before string into an int and compute the denominator such that 1.5 could become 15/10
int count = 0;
while (Math.abs(Math.round(before) - before) > 0.000001) {
before *= 10;
count++;
}
// Print debugging information
System.out.println(count);
// Compute the top of the combined fraction
int top = ((int)before)*bot+repeat;
bot = (int)Math.pow(10,count) * bot;
System.out.println(top+" "+bot);
// TODO: Reduce fraction
}
public static void main(String[] args) {
fraction("0.3",1);
fraction("1.580",2);
fraction("0.34",1);
fraction("0.34",2);
}
}
Note: You can't pass in the double 1.580 because that as a string is 1.58 not 1.580 as the 0 is omitted which messes up the function.
For Converting repeating decimals to fractions could you try the following:
import java.math.BigInteger;
public class ConvertRepeatingNumbersToFraction {
public static void main(String[] args) {
convertToFraction("0.3",1);
convertToFraction("1.580",2);
convertToFraction("0.16",1);
convertToFraction("0.34",2);
convertToFraction("0.42",2);
convertToFraction("0.34",1);
}
private static void convertToFraction(String x, int numOfRepeatingDigits) {
int denominator = 0;
for (int i = 0; i < numOfRepeatingDigits; i++) {
denominator = denominator * 10 + 9;
}
int repeatingNumber = Integer.valueOf(x.substring(x.length() - numOfRepeatingDigits));
double numerator = Double.valueOf(x.substring(0, x.length() - numOfRepeatingDigits));
int count = 0;
if (numerator % 1 != 0) {
numerator = numerator * 10;
count++;
}
numerator = numerator * denominator + repeatingNumber;
denominator = (int) Math.pow(10, count) * denominator;
int[] fraction = reduce((int)numerator, denominator);
System.out.println(fraction[0] + "/" + fraction[1]);
}
private static int[] reduce(int num, int den) {
// common divisor
int commonDivisor = BigInteger.valueOf(num).gcd(BigInteger.valueOf(den)).intValue();
return new int[]{ num / commonDivisor, den / commonDivisor };
}
}
I have checked the test numbers on http://onlinecalculators.brainmeasures.com/Numbers/RecurringDecimalNumbertoFraction.aspx and the result are the same.
Hope that helps :)

Calculating nth root in Java using power method

I was trying to get a cubic root in java using Math.pow(n, 1.0/3) but because it divides doubles, it doesn't return the exact answer. For example, with 125, this gives 4.9999999999. Is there a work-around for this? I know there is a cubic root function but I'd like to fix this so I can calculate higher roots.
I would not like to round because I want to know whether a number has an integer root by doing something like this: Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3)).
Since it is not possible to have arbitrary-precision calculus with double, you have three choices:
Define a precision for which you decide whether a double value is an integer or not.
Test whether the rounded value of the double you have is a correct result.
Do calculus on a BigDecimal object, which supports arbitrary-precision double values.
Option 1
private static boolean isNthRoot(int value, int n, double precision) {
double a = Math.pow(value, 1.0 / n);
return Math.abs(a - Math.round(a)) < precision; // if a and round(a) are "close enough" then we're good
}
The problem with this approach is how to define "close enough". This is a subjective question and it depends on your requirements.
Option 2
private static boolean isNthRoot(int value, int n) {
double a = Math.pow(value, 1.0 / n);
return Math.pow(Math.round(a), n) == value;
}
The advantage of this method is that there is no need to define a precision. However, we need to perform another pow operation so this will affect performance.
Option 3
There is no built-in method to calculate a double power of a BigDecimal. This question will give you insight on how to do it.
The Math.round function will round to the nearest long value that can be stored to a double. You could compare the 2 results to see if the number has an integer cubic root.
double dres = Math.pow(125, 1.0 / 3.0);
double ires = Math.round(dres);
double diff = Math.abs(dres - ires);
if (diff < Math.ulp(10.0)) {
// has cubic root
}
If that's inadequate you can try implementing this algorithm and stop early if the result doesn't seem to be an integer.
I wrote this method to compute floor(x^(1/n)) where x is a non-negative BigInteger and n is a positive integer. It was a while ago now so I can't explain why it works, but I'm reasonably confident that when I wrote it I was happy that it's guaranteed to give the correct answer reasonably quickly.
To see if x is an exact n-th power you can check if the result raised to the power n gives you exactly x back again.
public static BigInteger floorOfNthRoot(BigInteger x, int n) {
int sign = x.signum();
if (n <= 0 || (sign < 0))
throw new IllegalArgumentException();
if (sign == 0)
return BigInteger.ZERO;
if (n == 1)
return x;
BigInteger a;
BigInteger bigN = BigInteger.valueOf(n);
BigInteger bigNMinusOne = BigInteger.valueOf(n - 1);
BigInteger b = BigInteger.ZERO.setBit(1 + x.bitLength() / n);
do {
a = b;
b = a.multiply(bigNMinusOne).add(x.divide(a.pow(n - 1))).divide(bigN);
} while (b.compareTo(a) == -1);
return a;
}
To use it:
System.out.println(floorOfNthRoot(new BigInteger("125"), 3));
Edit
Having read the comments above I now remember that this is the Newton-Raphson method for n-th roots. The Newton-Raphson method has quadratic convergence (which in everyday language means it's fast). You can try it on numbers which have dozens of digits and you should get the answer in a fraction of a second.
You can adapt the method to work with other number types, but double and BigDecimal are in my view not suited for this kind of thing.
You can use some tricks come from mathematics field, to havemore accuracy.
Like this one x^(1/n) = e^(lnx/n).
Check the implementation here:
https://www.baeldung.com/java-nth-root
Here is the solution without using Java's Math.pow function.
It will give you nearly nth root
public class NthRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testcases = scanner.nextInt();
while (testcases-- > 0) {
int root = scanner.nextInt();
int number = scanner.nextInt();
double rootValue = compute(number, root) * 1000.0 / 1000.0;
System.out.println((int) rootValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static double compute(int number, int root) {
double xPre = Math.random() % 10;
double error = 0.0000001;
double delX = 2147483647;
double current = 0.0;
while (delX > error) {
current = ((root - 1.0) * xPre + (double) number / Math.pow(xPre, root - 1)) / (double) root;
delX = Math.abs(current - xPre);
xPre = current;
}
return current;
}
I'd go for implementing my own function to do this, possibly based on this method.
Well this is a good option to choose in this situation.
You can rely on this-
System.out.println(" ");
System.out.println(" Enter a base and then nth root");
while(true)
{
a=Double.parseDouble(br.readLine());
b=Double.parseDouble(br.readLine());
double negodd=-(Math.pow((Math.abs(a)),(1.0/b)));
double poseve=Math.pow(a,(1.0/b));
double posodd=Math.pow(a,(1.0/b));
if(a<0 && b%2==0)
{
String io="\u03AF";
double negeve=Math.pow((Math.abs(a)),(1.0/b));
System.out.println(" Root is imaginary and value= "+negeve+" "+io);
}
else if(a<0 && b%2==1)
System.out.println(" Value= "+negodd);
else if(a>0 && b%2==0)
System.out.println(" Value= "+poseve);
else if(a>0 && b%2==1)
System.out.println(" Value= "+posodd);
System.out.println(" ");
System.out.print(" Enter '0' to come back or press any number to continue- ");
con=Integer.parseInt(br.readLine());
if(con==0)
break;
else
{
System.out.println(" Enter a base and then nth root");
continue;
}
}
It's a pretty ugly hack, but you could reach a few of them through indenting.
System.out.println(Math.sqrt(Math.sqrt(256)));
System.out.println(Math.pow(4, 4));
System.out.println(Math.pow(4, 9));
System.out.println(Math.cbrt(Math.cbrt(262144)));
Result:
4.0
256.0
262144.0
4.0
Which will give you every n^3th cube and every n^2th root.
Find nth root Using binary search method.
Here is the way to find nth root with any precision according to your requirements.
import java.util.Scanner;
public class FindRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testCase = scanner.nextInt();
while (testCase-- > 0) {
double number = scanner.nextDouble();
int root = scanner.nextInt();
double precision = scanner.nextDouble();
double result = findRoot(number, root, precision);
System.out.println(result);
}
}
}
private static double findRoot(double number, int root, double precision) {
double start = 0;
double end = number / 2;
double mid = end;
while (true) {
if (precision >= diff(number, mid, root)) {
return mid;
}
if (pow(mid, root) > number) {
end = mid;
} else {
start = mid;
}
mid = (start + end) / 2;
}
}
private static double diff(double number, double mid, int n) {
double power = pow(mid, n);
return number > power ? number - power : power - number;
}
private static double pow(double number, int pow) {
double result = number;
while (pow-- > 1) {
result *= number;
}
return result;
}
}
I'm using this nth_root algorithm, which also provide the remainder :
public static BigInteger[] sqrt(final BigInteger n) {
final BigInteger[] res = {ZERO, n,};
BigInteger a, b;
assert (n.signum() > 0);
a = ONE.shiftLeft(n.bitLength() & ~1);
while (!a.equals(ZERO)) {
b = res[0].add(a);
res[0] = res[0].shiftRight(1);
if (res[1].compareTo(b) >= 0) {
res[1] = res[1].subtract(b);
res[0] = res[0].add(a);
}
a = a.shiftRight(2);
}
return res;
}
public static BigInteger[] nth_root(BigInteger n, final int nth) {
final BigInteger[] res;
switch(nth){
case 0 : res = new BigInteger[]{n.equals(ONE) ? ONE : ZERO, ZERO} ; break;
case 1 : res = new BigInteger[]{n, ZERO}; break;
case 2 : res = sqrt(n); break;
default:
int sign = n.signum() ;
n = n.abs();
res = new BigInteger[]{n.shiftLeft((n.bitLength() + nth - 1) / nth), n};
while(res[1].compareTo(res[0])<0) {
res[0] = res[1];
res[1] = BigInteger.valueOf(nth-1).multiply(res[1]).add(n.divide(res[1].pow(nth - 1))).divide(BigInteger.valueOf(nth));
}
res[1] = res[0].pow(nth);
res[1] = n.subtract(res[1]);
if (sign < 0 && (nth & 1) == 1) {
res[0] = res[0].negate();
res[1] = res[1].negate();
} else assert (sign > 0);
}
return res ;
}
}

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