DeathVenom
DeathVenom

Reputation: 394

I can't get the part of the code that is creating the problem

I'm making a fractions calculator and have finally settled on the design and how things work and have written the code. However, it almost never gives out the correct answer. I don't know why this is happening?

It uses a Fraction class I made which contains only 3 variables: numerator, denominator and whole.

The process involves the following:

Taking input from user and converting to a Fraction form

Calculating

Simplifying the result

and finally displaying the result.

The code:

package com.example.fraccalcinkotlin

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.widget.Toast
import androidx.core.text.isDigitsOnly
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        editText_number1_num.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int,
                                       before: Int, count: Int) {
                if (s.endsWith(" ")){
                    editText_number1_den.requestFocus()
                    editText_number1_num.setText(removeLastChar(editText_number1_num.text.toString()))
                }
            }
        })
        editText_number1_den.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int,
                                       before: Int, count: Int) {
                if (s.endsWith(" ") || s.endsWith("/")){
                    editText_number1_den.setText(removeLastChar(editText_number1_den.text.toString()))
                }
            }
        })
        editText_number1_whole.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (s.endsWith(" ")){
                    editText_number1_num.requestFocus()
                    editText_number1_whole.setText(removeLastChar(editText_number1_whole.text.toString()))
                }
            }
        })


        editText_number2_num.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (s.endsWith(" ")){
                    editText_number2_den.requestFocus()
                    editText_number2_num.setText(removeLastChar(editText_number2_num.text.toString()))
                }
            }
        })
        editText_number2_den.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (s.endsWith(" ") || s.endsWith("/")){
                    editText_number2_den.setText(removeLastChar(editText_number2_den.text.toString()))
                }
            }
        })
        editText_number2_whole.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {}
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (s.endsWith(" ")){
                    editText_number2_num.requestFocus()
                    editText_number2_whole.setText(removeLastChar(editText_number2_whole.text.toString()))
                }
            }
        })
        button_add.setOnClickListener {
            var sum:Fraction = AddNumbers()
            var num: Int = sum.numerator
            var den: Int = sum.denominator
            var whole: Int = sum.wholeNo
            var result_string: String = "$whole $num/$den"
            textView_result.text = result_string
        }
    }
    fun AddNumbers(): Fraction {
        //convert String to Fraction for calculations
        val num1: Int = editText_number1_num.text.toString().toInt()
        val den1: Int = editText_number1_den.text.toString().toInt()
        val whole1: Int = editText_number1_whole.text.toString().toInt()
        val fraction1: List<Int> = listOf(num1, den1, whole1)
        val num2: Int = editText_number2_num.text.toString().toInt()
        val den2: Int = editText_number2_den.text.toString().toInt()
        val whole2: Int = editText_number2_whole.text.toString().toInt()
        val fraction2: List<Int> = listOf(num2, den2, whole2)
        var frac_1: Fraction = fractionalize(fraction1)
        var frac_2: Fraction = fractionalize(fraction2)
        //extracting numerators and denominators from List<Int>
        var numerator1 = frac_1.numerator
        var denominator1 = frac_1.denominator
        var numerator2 = frac_2.numerator
        var denominator2 = frac_2.denominator
        //Getting common denominator and numerators for adding
        var commonDenominator: Int = 1
        if (denominator1 != denominator2){
            commonDenominator = getLCM(denominator1, denominator2)
            numerator1 *= commonDenominator/denominator1
            numerator2 *= commonDenominator/denominator2
        } else if (denominator1 == denominator2){
            commonDenominator = denominator1
        }
        //adding....
        var sumOfNumerators: Int = numerator1 + numerator2
        var result: Fraction = Fraction(sumOfNumerators, commonDenominator,0)
        //simplifying....
        result = simplify(result)
        return frac_1
    }
    fun fractionalize(fraction: List<Int>): Fraction{
        //Finds type of number (input) and converts to List<Int> with [numerator, denominator, whole number]
        var num = fraction[0]
        var den = fraction[1]
        var whole = fraction[2]
        if (whole != 0){
            num += whole * den
            whole = 0
        }
        val result: Fraction = Fraction(num, den, whole)
        return result
    }
    fun simplify(fraction:Fraction):Fraction{
        var numerator: Int = fraction.numerator
        var denominator: Int = fraction.denominator
        var whole_number: Int = fraction.wholeNo
        if (getHCF(numerator, denominator) != 1){
            numerator /= getHCF(numerator, denominator)
            denominator /= getHCF(numerator, denominator)
        }

        if (numerator> denominator){
            numerator %= denominator
            whole_number = numerator / denominator
        }
        if (numerator == denominator){
            whole_number += 1
            numerator = 0
            denominator = 1
        }
        var result: Fraction = Fraction(numerator, denominator, whole_number)
        return result
    }
    fun getHCF(num1: Int, num2: Int):Int{
        var dividend = Math.max(num1, num2)
        var divisor = Math.min(num1, num2)
        var remainder: Int = 1
        //calculating HCF using repeated division method
        do {
            remainder = dividend % divisor
            dividend = divisor
            divisor = remainder
        } while (remainder > 0)
        return dividend
    }
    fun getLCM(num1: Int, num2: Int): Int{
        //num1 * num2 = HCF * LCM
        //so, LCM = (num1 * num2) / HCF
        var result: Int = (num1 * num2)/getHCF(num1, num2)
        return result
    }
    fun removeLastChar(string: String): String{
        var result: String = string
        if (!string.isEmpty()){
            result = string.substring(0, string.length - 1);
        }
        return  result
    }

}

Please suggest me things I can do to find out which part is causing the problem.

Upvotes: 0

Views: 53

Answers (1)

Tenfour04
Tenfour04

Reputation: 93609

I think I see the error here in simplify:

    if (numerator> denominator){
        numerator %= denominator
        whole_number = numerator / denominator
    }

You have already changed the numerator variable to be the remainder, and then you use it to find the whole number. You need to swap the order of these two lines in the if statement.

It would be better practice to have all these operations on Fraction be part of the Fraction class itself. This is called encapsulation and is fundamental to robust software design. Bugs will be rarer and easier to resolve. Something like this (I didn't test the math):

data class Fraction(val num: Int, val den: Int, val whole: Int) {
    fun toPure(): Fraction {
        return Fraction(num + whole * den, den, 0)
    }

    fun toSimplified(withWhole: Boolean): Fraction {
        with(toPure()) {
            val gcm = findGcf(num, den)
            val simplified = Fraction(num / gcm, den / gcm, 0)
            return if (!withWhole || num < den)
                simplified
            else
                Fraction(simplified.num % simplified.den, simplified.den, simplified.num / simplified.den)
        }
    }

    operator fun plus(other: Fraction): Fraction {
        val newDen = den * other.den
        val newNum = num * other.den + other.num * den
        return Fraction(newNum, newDen, whole + other.whole).toSimplified(true)
    }

    private fun findGcf(num1: Int, num2: Int): Int {
        var dividend = max(num1, num2)
        var divisor = min(num1, num2)
        var remainder: Int = 1
        //calculating HCF using repeated division method
        do {
            remainder = dividend % divisor
            dividend = divisor
            divisor = remainder
        } while (remainder > 0)
        return dividend
    }
}

To avoid repeating yourself, you can create a function for converting EditText content to a Fraction:

private fun getFraction(numET: EditText, denET: EditText, wholeET: EditText): Fraction? {
    val num = numET.text.toIntOrNull() ?: return null
    val den = denET.text.toIntOrNull() ?: return null
    val whole = wholeT.text.toIntOrNull() ?: return null
    return Fraction(num, den, whole)
}

Then your addNumbers function is a lot simpler:

fun addNumbers(): Fraction? {
    val first = getFraction(editText_number1_num, editText_number1_den, editText_number1_whole) ?: return null
    val second = getFraction(editText_number2_num, editText_number2_den, editText_number2_whole) ?: return null
    return first + second
}

I made the return type nullable for the case of invalid input. Your click listener that uses addNumbers can show an error message instead of the Fraction if the input is invalid.

Upvotes: 1

Related Questions