Trying Junit for the first time and failing - java

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.

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.

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 :)

Why doesn't my stackSize method work?

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;
}

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++){
}

why does this value not change when I turn it into a negative?

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

Categories