1 year ago

#304913

test-img

jPark197

Kotlin BigDecimal rounding to decimal point based on how large number is

I am building a simple calculator in Kotlin (first project) that uses BigDecimal precision. I have found with the current program that inputting 9% x 3% for example (0.09 x 0.03) will output 0.002699999999999... when it should output 0.0027?

I've experimented with DecimalFormat and some rounding methods but I don't want to round every number to .00 decimal places.

Question 1: How can I make this dynamic - so if the result is 0.0123 it will round to 0.012 and if the answer is 0.0000456 it will round to 0.000047. Only rounding up to the last two actual numbers that are not zero but ignoring the amount of prepending zeros.

Question 2: How can I implement scientific notation? I.E. if the number is larger than 15 digits format to append E etc

Question 3: Is there a way to format the displayNum string to display something like 1,000,000.032 ?

Currently if I use :

val df = DecimalFormat("#,###")
textView.text = df.format(numBigDecimal)

The app will crash or not display the decimal if I try to add a decimal point

Question 4: If the number starts at BigDecimal.ZERO and I press button +/- to run the toggleCalc() function to turn the number to "-" negative and I then press the button to add a decimal . (setDouble() function) and add another zero it reverts the number to a positive zero.

Example: -0. to -0.0 returns 0.0 on displayNum & currentNum values (not working - if I press toggleCalc button on 0.0 it will return -0.0 and work thereafter but not in above example)

Example 2: -0. to -0.3 returns -0.3 on displayNum & currentNum values (working)

If I try to manipulate what is shown on the textField instead the currentNum does not update and cannot run the math appropriately. I've found that BigDecimal cannot return a -0 even with BigDecimal.negate()

enum class LogicTypes {
    None,Add,Subtract,Multiply,Divide,Percent
}

class MainActivity : AppCompatActivity() {

    private var logicActive = false
    private var currentLogic = LogicTypes.None
    private var currentNum: BigDecimal = BigDecimal.ZERO
    private var displayNum = ""

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView.text = "0"
        calcInit()
    }

    fun calcInit() {
        val buttons = arrayOf(button_zero, button_1, button_2, button_3,
            button_4, button_5, button_6, button_7, button_8, button_9)
        for(i in buttons.indices) {
            buttons[i].setOnClickListener { addNum(i.toBigDecimal()) }
        }
        button_addition.setOnClickListener { changeLogic(LogicTypes.Add) }
        button_subtraction.setOnClickListener { changeLogic(LogicTypes.Subtract) }
        button_multiply.setOnClickListener { changeLogic(LogicTypes.Multiply) }
        button_division.setOnClickListener { changeLogic(LogicTypes.Divide) }
        button_dot.setOnClickListener { setDouble() }
        button_equals.setOnClickListener { calculate() }
        button_clear.setOnClickListener { clearCalc() }
        button_percent.setOnClickListener { calcPercent() }
        button_plus_minus.setOnClickListener { toggleCalc() }
    }

    fun calcPercent() {
//        if (currentLogic != LogicTypes.None) {
//            return
//        }
        var percentNum = displayNum.toDouble()
        percentNum /= 100
        displayNum = "$percentNum"
        textView.text = displayNum
        if(currentLogic == LogicTypes.None) {
            currentNum = displayNum.toBigDecimal()
        }
//        updateDisplayNum()
    }

    fun toggleCalc() {
        if(displayNum.contains("-")) {
            displayNum = displayNum.replace("-", "")
        } else {
            if(currentNum == BigDecimal.ZERO) {
                displayNum = "-0"
            } else {
                displayNum = "-$displayNum"
            }
        }
        val numBigDecimal = displayNum.toBigDecimal()

        if(currentLogic == LogicTypes.None) {
            currentNum = numBigDecimal
        }
        textView.text = displayNum
    }

    fun clearCalc() {
        logicActive = false
        currentLogic = LogicTypes.None
        displayNum = ""
        currentNum = BigDecimal.ZERO
        textView.text = "0"
        hintView.text = ""
    }

    fun calculate() {
        if (logicActive) {
            return
        }
        val numBigDecimal = displayNum.toDouble()
        var doubleNum = currentNum.toDouble()

        val doubleNumString = doubleNum.toString()
        val numBigDecimalString = numBigDecimal.toString()

        val addMsg = getString(R.string.calc_message, doubleNumString, "+", numBigDecimalString)
        val subMsg = getString(R.string.calc_message, doubleNumString, "-", numBigDecimalString)
        val multiMsg = getString(R.string.calc_message, doubleNumString, "*", numBigDecimalString)
        val divMsg = getString(R.string.calc_message, doubleNumString, "/", numBigDecimalString)

      when(currentLogic) {
            LogicTypes.Add -> {
                hintView.text = addMsg
                doubleNum += numBigDecimal
            }
            LogicTypes.Subtract -> {
                hintView.text = subMsg
                doubleNum -= numBigDecimal
            }
            LogicTypes.Multiply -> {
                hintView.text = multiMsg
                doubleNum *= numBigDecimal
            }
            LogicTypes.Divide -> {
                hintView.text = divMsg
                doubleNum /= numBigDecimal
            }
            LogicTypes.None -> return
        }

        currentLogic = LogicTypes.None
        displayNum = "$doubleNum"
        Log.i(LOG_TAG, displayNum)
        updateDisplayNum()
        logicActive = true
    }

    fun changeLogic(mode: LogicTypes) {
//        if(currentNum == BigDecimal.ZERO) {
//            return
//        }
        currentLogic = mode
        logicActive = true
    }

    fun updateDisplayNum() {
//        if (displayNum.length > 15) {
//            clearCalc()
//            Toast.makeText(this, "Maximum of 15 digits allowed.", Toast.LENGTH_SHORT).show()
//            return
//        }
        val numBigDecimal = displayNum.toBigDecimal()
        displayNum = numBigDecimal.toString()

        if(currentLogic == LogicTypes.None) {
            currentNum = numBigDecimal
        }

//        val df = DecimalFormat("#,###")
//        textView.text = df.format(numBigDecimal)
        textView.text = displayNum
    }

    fun addNum(num: BigDecimal) {
        val inputNum = num.toString()
        if (logicActive) {
            logicActive = false
            displayNum = "0"
        }
        displayNum = "$displayNum$inputNum"
        updateDisplayNum()
    }

    fun setDouble() {
        if(displayNum.contains(".")) {
            return
        }
        if(currentNum == BigDecimal.ZERO && displayNum.contains("-")) {
            displayNum = "-0."
        } else if (currentNum == BigDecimal.ZERO) {
            displayNum = "0."
        } else {
            displayNum = "$displayNum."
        }

        textView.text = displayNum
    }
}

android

kotlin

calculator

bigdecimal

scientific-notation

0 Answers

Your Answer

Accepted video resources