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.
Related
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.
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 ;
}
}
My objective is to provide a class Stacker that contains a method stackSize that takes an int called extension as its parameter. It should return the smallest long n such that the sum of the sequence 1/2 + 1/4 + 1/6 + 1/8 + ... + ... + 1/2n is greater than or equal to extension.
Assuming my Rat class (Rational Number) correctly adds up two fractions using the first parameter as a numerator and the second parameter as a denominator, any ideas why this code isn't working for me?
The default Rat() constructor simply makes the Rational number (0/1) and the Rat(extension) constructor makes the Rational number (extension/1).
public class StackerTest {
#Test
public void test1()
{
assertEquals(4, Stacker.stackSize(1));
}
}
When I run the test case:
#Test
public void test1()
{
assertEquals(4, Stacker.stackSize(1));
}
It runs for a solid 30 seconds before giving an IllegalArgumentException
Here is the constructor for Rat class as well as the add method
/**
* If d is zero, throws an IllegalArgumentException. Otherwise creates the
* rational number n/d
*/
public Rat (int n, int d)
{
// Check parameter restriction
if (d == 0)
{
throw new IllegalArgumentException();
}
// Adjust sign of denominator
num = n;
den = d;
if (den < 0)
{
num = -num;
den = -den;
}
// Zero has a standard representation
if (num == 0)
{
den = 1;
}
// Factor out common terms
int g = gcd(Math.abs(num), den);
num = num / g;
den = den / g;
}
/**
* Returns the sum of this and r
*/
public Rat add (Rat r)
{
int firstNum = this.num*r.den;
int firstDen = this.den*r.den;
int secondNum = r.num*this.den;
int secondDen = r.den*this.den;
Rat x = new Rat(firstNum+secondNum, firstDen);
return x;
}
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++){
}
I am trying to write a class Rational that had a few methods relating to adding, subtracting, etc. I want to make it so that within the constructor, I add the values to the private variables and find the GCD to find simplify the fraction. The problem I run into is with my if statements. I want to check if the numbers within the object parameter are negative so I use the if statement to check. The only problem is when I run the program, it doesn't give me a negative value i.e. I have Rational p = new Rational(-24, 48) and it only returns 1/2.
public class TestRational {
public static void main(String... args) {
Rational p = new Rational(-24, 48);
}
public Rational(long a, long b){
numerator = a;
denominator = b;
boolean isNegative = false;
if (numerator*denominator < 0)
isNegative = true;
long gd = gcd(numerator, denominator);
numerator /= gd;
denominator /= gd;
if (isNegative)
numerator = -numerator;;
}
private long gcd(long p, long q){
//checks to see if numerator greater than denominator
if(p<q)
return gcd(q,p);
if(Math.abs(q) == 0)
return p;
long remainder = Math.abs(p)%Math.abs(q);
return gcd(Math.abs(q), Math.abs(remainder));
}
}
You dont need this
if (isNegative)
numerator = -numerator;;
So the constructor becomes
public Rational(long a, long b){
numerator = a;
denominator = b;
boolean isNegative = false;
if (numerator*denominator < 0)
isNegative = true;
long gd = gcd(numerator, denominator);
numerator /= gd;
denominator /= gd;
}
Hope it works ...
Unless your question asked you explicitly to use GCD and the range of a and b is not big, you can implement it simply with a loop:
public Rational(long a, long b){
boolean isNegative = a < 0 || b < 0;
a = Math.abs(a);
b = Math.abs(b);
for (int i = min(a, b); i >= 2; --i)
if (a % i == 0 && b % i == 0)
{
a /= i;
b /= i;
}
numerator = isNegative ? -a : a;
denominator = b;
}
i would like point some "avoidable mistakes" in your code.
Name of constructor must be same as name of class. In your case it is not.
use blocks for if{ statements} even if it contains single statement.
you have not declared type of local variable numerator and denominator
what private variables you are talking about ?
Pay little more attention to code while posting, it will help you to get good answers to your question