1

While there are many rounding questions answered in StackO., I could not quite translate this to my multi-part question. (I am not sure why the link at the top of my post says "answer is here"... because this feels more like a resource to me, one that, for a beginner, is very difficult to sift through. I would not have come up with the answer someone presented on my post, just by looking through all of that conversation and analyzing the link for RoundingMode on that page. I see part of the right code is there, but only after it has been pointed out to me by someone who knew the answer.)

1. I need to round my finalBill TextView field so that it is to 2 decimal places. I heard using BigDecimal is good, but don't know how to write it, or where to put it in my code (I am a beginner).

2. Would it be more wise to round the double variable (within my onClick methods), before I convert to a String? Or would it be better to round the final answer that is delivered in a String (in the finalBill TextView field)?

Right now, I get the final answer that has many, many decimals behind it. I just need 2.

Backstory: I am creating a tip calculator, and when the onClick method executes for each button (10%, 15%, and 20%)... this should calculate the new total bill that includes tip, and also give the numeric answer (which has already been converted to a TextView) in a number no more than 2 decimal points. Thanks for your help!

Here is my code: I only included the amount including the first method onTen, since this method is where the tip is calculated and where the rounding needs to happen. (Other buttons not included for simplicity sake).

package com.example.nonitips;

import java.math.BigDecimal;
import java.math.RoundingMode;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

    private EditText originalBill;
    private double billWithTip; 
    String billString;
    private TextView finalBill;
    private Button btnTen;
    private Button btnFifteen;
    private Button btnTwenty;
    double rounder = billWithTip;


    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        originalBill = (EditText)findViewById(R.id.originalBill);
    }

    public void onTen (View v) {
        //Toast.makeText(this, "Tipping at 10%", Toast.LENGTH_SHORT).show();

        btnTen = (Button)findViewById(R.id.btnTen);
        //The button gets the setOnClickListener
        btnTen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                double bill = Double.parseDouble(originalBill.getText().toString());
                billWithTip = bill * 1.10;
                //Turns the answer back into a string
                String billString = String.valueOf(billWithTip);
                finalBill = (TextView)findViewById(R.id.finalBill);
                finalBill.setText(billString);
            }
        }); 
    }

}
Azurespot
  • 3,066
  • 3
  • 45
  • 73
  • Is all that code really necessary? – Christian Tapia Mar 25 '14 at 21:26
  • Please distill your question down to the code computing the result - your display, etc are not of interest. – KevinDTimm Mar 25 '14 at 21:27
  • I cut down some of the code. Can people please not downvote so quickly? I am a beginner, it takes some time to look things up and think about things. Thank you. – Azurespot Mar 25 '14 at 21:37
  • 1
    @NoniA. : I didn't personally downvote but a piece of advice here on SO is not to post a sizeable chunk of code which is mostly Android-specific and then stick a "Java" tag on the question. Not all Java programmers program for Android and, in my experience, very many don't understand the fundamentals. In this case you could have simply posted the Java code and explained you just wan't to round a number represented by a string of text to 2 decimal places. – Squonk Mar 25 '14 at 21:49
  • Oh goodness, thanks for explaining that, I thought I selected Android, but I must have accidentally not selected it. That is very good advice. Thanks so much! It was just the onTen method, that is where the code is, and specifically the onClick() method is where I need to change the value of finalBill (which is a TextView) into a round number to 2 decimal places. – Azurespot Mar 25 '14 at 22:09
  • Hmm, that is strange, actually I see an Android tag on my post.. I wonder if it was hidden somehow when I posted? – Azurespot Mar 25 '14 at 22:10
  • Okay, I think I will delete/rewrite the post, there are a lot of trial and errors, but thanks for those who tried. :/ – Azurespot Mar 25 '14 at 22:21
  • 1
    @NoniA. Please don't delete this. The site will lose all the value that's in the answers here. – Dawood ibn Kareem Mar 25 '14 at 22:23
  • Okay, thanks David for the advice. I was going to write a maybe better version of it, but I see one person came up with a solution, so it was good to wait it out! (Plus it's good to know it's better not to delete, I was not clear about that). :) – Azurespot Mar 25 '14 at 22:25
  • 1
    @NoniA. : You did put the "Android" tag on the question as well as the "Java" tag. My point was simply that your issue was primarily a Java question but not all Java programmers are Android programmers and by including a lot of Android-specific code puts a lot of Java programmers off (and sometimes attracts downvoting). – Squonk Mar 25 '14 at 22:55
  • Thanks Squonk. To be honest, it's hard to tell sometimes whether it's mostly Android or mostly Java (as a beginner), but I will try to keep this in mind for the future. Thanks for explaining. – Azurespot Mar 25 '14 at 23:54
  • 1
    I don't feel this is a duplicate of that other question. Noni wants to have two decimal places and avoid rounding errors in code that parses a String, does a multiplication, then converts back to a String. The correct solution, of course, involves BigDecimals. The other question is specifically about rounding a double, so any correct solution to the other question is not a correct solution to _this_ question. I have voted to reopen. – Dawood ibn Kareem Mar 26 '14 at 00:07

4 Answers4

2

Here's what I think you mean

BigDecimal n = new BigDecimal("1.1111111111111"); n = n.setScale(2, BigDecimal.ROUND_CEILING);

RoverMAX
  • 89
  • 6
1

As for the first question:

1.) I'd suggest you use the method explained in:

How to round a number to n decimal places in Java. It is well explained there.

And the second one:

2.) I would personally just round the final answer.

EDIT: After a lot of bugs as pointed by Dave this is the final code:

Instead of the statement:

double bill = Double.parseDouble(originalBill.getText().toString());

You need to write and add:

BigDecimal bill = new BigDecimal(originalBill.getText().toString());
BigDecimal tax = new BigDecimal("1.10");     
BigDecimal billWithTax = modifiedBill.multiply(tax);
BigDecimal roundedBill = billWithTax.setScale(2,RoundingMode.HALF_UP);

And change the next line in your code to:

String billString = String.valueOf(roundedBill);

Also you will need to import

java.math.BigDecimal;
java.math.RoundingMode;

Also, do note that you would have to change the earlier declaration of billWithTax being a double.

Community
  • 1
  • 1
Sid
  • 234
  • 1
  • 4
  • 14
  • Thanks Sid, you are very nice. I looked at that link, as suggested by someone else too, but I did not understand what I am supposed to use.. the setRoundingMode? I did not understand from the setRoundingMode page which method might be best for what I need. :/ – Azurespot Mar 25 '14 at 22:05
  • I added the code you would need to the post. To make things simpler, you could just define the 'billWithTip' variable as a BigDecimal in the first place. But the code I wrote is assuming that billWithTip is a double. – Sid Mar 25 '14 at 22:20
  • Awesome, thanks!! Concise code... very nice. And especially thanks for taking the time to apply it to my situation. I know people think new people are lazy sometimes, but we just can't put things together in our heads when we get a bunch of links and general advice to use certain classes or methods. So I really appreciate that help! – Azurespot Mar 25 '14 at 22:27
  • Oh, and what do you think about BigDecimal versus DecimalFormat? Is BigDecimal slower in your experience? – Azurespot Mar 25 '14 at 22:28
  • 1
    Really glad I could help out. I completely understand that it can be difficult with links. And I am pretty much an android beginner myself, so don't worry about that either. Happy coding and good luck. RE: BigDecimal versus DecimalFormat: I have been using BigDecimal for most of my java apps and I have not noticed any performance issues but that being said, my java apps have not necessarily been data intensive for me to encounter performance issues. So, for a calculator, I believe BigDecimal will work perfectly well. – Sid Mar 25 '14 at 22:30
  • 1
    Edited with my take on BigDecimal. – Sid Mar 25 '14 at 22:32
  • 1
    This answer is incorrect in two regards (I want to downvote it but I am unable to remove my earlier upvote) - for example, it turns 11.50 into 12.66, whereas 12.65 would be correct. Firstly, you don't want `RoundingMode.UP`, because it rounds any fraction of a cent upwards, not just fractions that are half a cent or more. Secondly, you want to do the conversion to BigDecimal before the multiplication, not after, since it's the multiplication that introduces floating point problems. Converting to BigDecimal after the multiplication has occurred has absolutely no effect. – Dawood ibn Kareem Mar 26 '14 at 00:25
  • I'd have to look into the RoundingMode.UP and get back. However, it is required after the multiplication since that is when the decimals will come into play. Say, my bill is 10$, BigDecimal won't do much there. However when it is 10*1.10 , that's where I need the rounding up. I hope I understood you correctly. – Sid Mar 26 '14 at 00:28
  • EDIT: Also, it didn't turn 11.50 to 12.66 for me I get what you mean with the any fraction of a cent being rounded upwards and I changed that with the HALF_UP – Sid Mar 26 '14 at 00:35
  • OK, the change from UP to HALF_UP is correct, but you still have the second problem that I mentioned. You need for the actual multiplication to be done with BigDecimals, not with doubles, otherwise the floating point error creeps in. Converting a double with an error to a BigDecimal won't take away the error. For example, even with HALF_UP rounding, 11.95 will become 13.04, where it should be 13.05. I would post a correct answer myself if the question hadn't been incorrectly closed - but the gist of it is that you need to parse the original String into a BigDecimal and work with that. – Dawood ibn Kareem Mar 26 '14 at 00:54
  • I see the second problem. For some reason, with BigDecimal, 11.95*1.10 results into 13.1449999999 Rather than 13.145 – Sid Mar 26 '14 at 01:03
  • No, that's what happens with double. Then you convert the incorrect double to a BigDecimal afterwards. You need to do the conversion to BigDecimal before the multiplication, and multiply two BigDecimal values together. – Dawood ibn Kareem Mar 26 '14 at 01:11
  • Fixed it just before you commented, was running a few tests to ensure it was okay. Does it look alright now? – Sid Mar 26 '14 at 01:13
  • Also, thank you for minutely going through the possibilities and pointing out the mistakes. I really appreciate it. – Sid Mar 26 '14 at 01:18
  • 1
    I'm not sure. It still doesn't seem quite right to me, but I'll need to check more carefully now, and look harder for a case that doesn't work. Basically, the constructor `BigDecimal(double value)` can cause problems, and the constructor `BigDecimal(String value)` is safer. So I would have written `new BigDecimal(originalBill.getText())` and also `new BigDecimal("1.10")` (with the `""`) - that is, always pass Strings not doubles. I will comment (and possibly upvote) again after I've done a more thorough check. I removed my downvote. – Dawood ibn Kareem Mar 26 '14 at 02:21
  • 1
    OK, with a tax rate of 1.1, your method will always work. To find a problem, I changed the tax rate to 1.7, and multiplied it by 11.75. The correct answer is 19.98, but your method gives 19.97. My advice is only ever to create a `BigDecimal` from a `String` or from a whole number - never from a `double` with decimal places. And never use a `double` for an amount of money, no matter how briefly. – Dawood ibn Kareem Mar 26 '14 at 02:47
  • Wow. That's some amazing testing, taking 1.7 too, something I hadn't attempted. If only I could test as thoroughly. I have now made the change of passing Strings instead. I am slightly surprised doubles cause so many problems but more surprised that it takes so much to round off decimals in Java. Thank you for removing the down vote but more, thanks a lot for pointing out the issues, I learnt a lot through this for myself. – Sid Mar 26 '14 at 10:45
0

Use this method:

public static String getDoubleAsFormattedDoubleToEdit(String valueS) {
    DecimalFormatSymbols simbolos = new DecimalFormatSymbols();
    simbolos.setGroupingSeparator(',');
    simbolos.setDecimalSeparator('.');
    double value = Double.valueOf(Util.typeCorrection(ETipoDato.FLOTANTE, 0, true, valueS));
    return new DecimalFormat("###.##", simbolos).format(value);
}

This way you can pass your value and the return is your value formatted.

Laura Pulido
  • 161
  • 5
  • Thanks for sharing that, a person above had a very short piece of code so I tried that and it worked... I might have had many questions with your code block as well, some things I never saw before... but thanks anyway! – Azurespot Mar 25 '14 at 22:29
  • What library are you using, that contains something as quaint as an `ETipoDato.FLOTANTE`? – Dawood ibn Kareem Mar 26 '14 at 00:09
-1

Use a DecimalFormat object.

float f = 9.999f;

DecimalFormat df = new DecimalFormat("00.00");

System.out.println(df.format(f));

It will print 10.00. Do not use BigDecimal, it is slower than DecimalFormat.

9.999f is the value that you want to round. But you can also use a double value :

double bill = Double.parseDouble(originalBill.getText().toString());
billWithTip = bill * 1.10;
DecimalFormat df = new DecimalFormat("#.##");
// the #.## means that you want 2 decimals places
billString = df.format(billWithTip);
Moussamoa
  • 417
  • 1
  • 4
  • 19
  • Thanks so much for that tip. What is 9.999f? I am trying to think of how this will translate into the code I have. Or is that something that needs to be there? I don't know how to integrate this with my code. (beginner) :/ – Azurespot Mar 25 '14 at 21:41
  • Oh great thanks. Although my teacher said many times not to use float, as it is not very precise... although I don't know if that matters since I am just using it for dollars and cents. What do you think? – Azurespot Mar 25 '14 at 21:45
  • 1
    I edited my post, just look :) (and sorry for my bad english) – Moussamoa Mar 25 '14 at 21:50
  • Moussamoa, do I need to use the f at all next to my variable name (in place of 9.999f)? Because the answer will vary every time the user enters a bill amount, and then presses the % of tip button. Do I just use my variable name that represents the amount after it's calculated? – Azurespot Mar 25 '14 at 21:53
  • 1
    You don't need the f variable, please see my post above. I edited it. – Moussamoa Mar 25 '14 at 21:54
  • Darn, it did not work... when I try a bill of 100, it comes back with many decimal points... :( here is what I used: `DecimalFormat df = new DecimalFormat("#.##"); billString = df.format(billWithTip);` – Azurespot Mar 25 '14 at 21:59