title: Using BigDecimal causes slight error in calculations
body: <p>I'm writing a basic unit converter for android. This is my program:</p>
  
  <pre><code>package com.airavataunitconverter;
  
  import java.math.BigDecimal;
  import java.math.MathContext;
  import java.math.RoundingMode;
  import java.text.DecimalFormat;
  
  import com.airavataunitconverter.R.id;
  
  import android.app.Activity;
  import android.content.Context;
  import android.content.SharedPreferences;
  import android.content.SharedPreferences.Editor;
  import android.graphics.Typeface;
  import android.os.Bundle;
  import android.text.Editable;
  import android.text.TextWatcher;
  import android.view.Menu;
  import android.view.View;
  import android.widget.AdapterView;
  import android.widget.AdapterView.OnItemSelectedListener;
  import android.widget.ArrayAdapter;
  import android.widget.EditText;
  import android.widget.Spinner;
  import android.widget.TextView;
  
  public class LengthConverter extends Activity {
    Spinner spr_unit_l;
    EditText et_input_l;
    TextView tv_result_nm;
    TextView tv_result_mm;
    TextView tv_result_cm;
    TextView tv_result_dm;
    TextView tv_result_m;
    TextView tv_result_km;
    TextView tv_result_in;
    TextView tv_result_ft;
    TextView tv_result_yd;
    TextView tv_result_mi;
    TextView tv_result_nmi;
    TextView tv_nm;
    TextView tv_mm;
    TextView tv_cm;
    TextView tv_dm;
    TextView tv_m;
    TextView tv_km;
    TextView tv_in;
    TextView tv_ft;
    TextView tv_yd;
    TextView tv_mi;
    TextView tv_nmi;
    BigDecimal nm;
    BigDecimal mm;
    BigDecimal cm;
    BigDecimal dm;
    BigDecimal m;
    BigDecimal km;
    BigDecimal in ;
    BigDecimal ft;
    BigDecimal yd;
    BigDecimal mi;
    BigDecimal nmi;
    BigDecimal zero;
    BigDecimal bd_input_number_length;
    String str_nm = "nanometer";
    String str_mm = "millimeter";
    String str_cm = "centimeter";
    String str_dm = "decimeter";
    String str_m = "meter";
    String str_km = "kilometer";
    String str_in = "inch";
    String str_ft = "feet";
    String str_yd = "yard";
    String str_mi = "mile";
    String str_nmi = "nautical mile";
    String STR_INPUT_UNIT_LENGTH;
    int input_unit_length;
    int int_input_unit_length;
    String STR_INPUT_NUMBER_LENGTH;
    String str_unit_length;
    ArrayAdapter &lt; String &gt; myAdap;
    int unit_selected_nm;
    int unit_selected_mm;
    int unit_selected_cm;
    int unit_selected_dm;
    int unit_selected_m;
    int unit_selected_km;
    int unit_selected_in;
    int unit_selected_ft;
    int unit_selected_yd;
    int unit_selected_mi;
    int unit_selected_nmi;
    String input_number_length;
    BigDecimal bd_referance;
    BigDecimal bd_nm;
    BigDecimal bd_mm;
    BigDecimal bd_cm;
    BigDecimal bd_dm;
    BigDecimal bd_m;
    BigDecimal bd_km;
    BigDecimal bd_in;
    BigDecimal bd_ft;
    BigDecimal bd_yd;
    BigDecimal bd_mi;
    BigDecimal bd_nmi;
    @
    Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_length_converter);
      spr_unit_l = (Spinner) findViewById(R.id.spinner_length_unit);
      nm = new BigDecimal(0.000000001);
      mm = new BigDecimal(.001);
      cm = new BigDecimal(0.01);
      dm = new BigDecimal(0.1);
      m = new BigDecimal(1);
      km = new BigDecimal(1000); in = new BigDecimal(0.0254);
      ft = new BigDecimal(0.3048);
      yd = new BigDecimal(0.9144);
      mi = new BigDecimal(1609.344);
      nmi = new BigDecimal(1852);
      zero = BigDecimal.ZERO;
      String str_unit_length[] = {
        str_nm, str_mm, str_cm, str_dm, str_m,
        str_km, str_in, str_ft, str_yd, str_mi, str_nmi
      };
      myAdap = new ArrayAdapter &lt; String &gt; (this,
        android.R.layout.simple_spinner_item, str_unit_length);
      myAdap.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      spr_unit_l.setAdapter(myAdap);
      sharedpref = getSharedPreferences(MyPreferences, Context.MODE_PRIVATE);
      et_input_l = (EditText) findViewById(R.id.edittext_length_input);
      tv_nm = (TextView) findViewById(R.id.textview_nm);
      tv_mm = (TextView) findViewById(R.id.textview_mm);
      tv_cm = (TextView) findViewById(R.id.textview_cm);
      tv_dm = (TextView) findViewById(R.id.textview_dm);
      tv_m = (TextView) findViewById(R.id.textview_m);
      tv_km = (TextView) findViewById(R.id.textview_km);
      tv_in = (TextView) findViewById(R.id.textview_in);
      tv_ft = (TextView) findViewById(R.id.textview_ft);
      tv_yd = (TextView) findViewById(R.id.textview_yd);
      tv_mi = (TextView) findViewById(R.id.textview_mi);
      tv_nmi = (TextView) findViewById(R.id.textview_nmi);
      tv_result_nm = (TextView) findViewById(R.id.textview_result_nm);
      tv_result_mm = (TextView) findViewById(R.id.textview_result_mm);
      tv_result_cm = (TextView) findViewById(R.id.textview_result_cm);
      tv_result_dm = (TextView) findViewById(R.id.textview_result_dm);
      tv_result_m = (TextView) findViewById(R.id.textview_result_m);
      tv_result_km = (TextView) findViewById(R.id.textview_result_km);
      tv_result_in = (TextView) findViewById(R.id.textview_result_in);
      tv_result_ft = (TextView) findViewById(R.id.textview_result_ft);
      tv_result_yd = (TextView) findViewById(R.id.textview_result_yd);
      tv_result_mi = (TextView) findViewById(R.id.textview_result_mi);
      tv_result_nmi = (TextView) findViewById(R.id.textview_result_nmi);
      spr_unit_l.setOnItemSelectedListener(new OnItemSelectedListener() {
  
        @
        Override
        public void onItemSelected(AdapterView &lt;? &gt; arg0, View arg1,
          int arg2, long arg3) {
          // TODO Auto-generated method stub
          final_length_convert();
  
        }
  
        @
        Override
        public void onNothingSelected(AdapterView &lt;? &gt; arg0) {
          // TODO Auto-generated method stub
  
        }
  
      });
      et_input_l.addTextChangedListener(new TextWatcher() {
  
        @
        Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2,
          int arg3) {
          // TODO Auto-generated method stub
          final_length_convert();
  
        }
  
        @
        Override
        public void beforeTextChanged(CharSequence arg0, int arg1,
          int arg2, int arg3) {
          // TODO Auto-generated method stub
  
        }
  
        @
        Override
        public void afterTextChanged(Editable arg0) {
          // TODO Auto-generated method stub
  
        }
      });
  
    }
  
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.length_converter, menu);
      return true;
    }
  
    private int getIndex(Spinner spinner, String myString) {
  
      int index = 0;
  
      for (int i = 0; i &lt; spinner.getCount(); i++) {
        if (spinner.getItemAtPosition(i).equals(myString)) {
          index = i;
          i = spr_unit_l.getCount();
        }
      }
      return index;
    }
  
    private void final_length_convert() {
      if (et_input_l.getText().toString().equals("") || et_input_l.getText().toString().equals(".") || et_input_l.getText().toString().equals("-")) {
        tv_result_nm.setText(zero.toPlainString());
        tv_result_mm.setText(zero.toPlainString());
        tv_result_cm.setText(zero.toPlainString());
        tv_result_dm.setText(zero.toPlainString());
        tv_result_m.setText(zero.toPlainString());
        tv_result_km.setText(zero.toPlainString());
        tv_result_in.setText(zero.toPlainString());
        tv_result_ft.setText(zero.toPlainString());
        tv_result_yd.setText(zero.toPlainString());
        tv_result_mi.setText(zero.toPlainString());
        tv_result_nmi.setText(zero.toPlainString());
      } else if (spr_unit_l.getSelectedItem().equals(str_nm)) {
        bd_referance = nm;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_mm)) {
        bd_referance = mm;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_cm)) {
        bd_referance = cm;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_dm)) {
        bd_referance = dm;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_m)) {
        bd_referance = m;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_km)) {
        bd_referance = km;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_in)) {
        bd_referance = in ;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_ft)) {
        bd_referance = ft;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_yd)) {
        bd_referance = yd;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_mi)) {
        bd_referance = mi;
        length_convert();
      } else if (spr_unit_l.getSelectedItem().equals(str_nmi)) {
        bd_referance = nmi;
        length_convert();
      }
  
    }
  
    private void length_convert() {
      bd_input_number_length = new BigDecimal(et_input_l.getText().toString());
      bd_nm = bd_input_number_length.multiply(
          (bd_referance).divide(nm, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_mm = bd_input_number_length.multiply(
          (bd_referance).divide(mm, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_cm = bd_input_number_length.multiply(
          (bd_referance).divide(cm, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_dm = bd_input_number_length.multiply(
          (bd_referance).divide(dm, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_m = bd_input_number_length.multiply(
          (bd_referance).divide(m, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_km = bd_input_number_length.multiply(
          (bd_referance).divide(km, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_in = bd_input_number_length.multiply(
          (bd_referance).divide( in , 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_ft = bd_input_number_length.multiply(
          (bd_referance).divide(ft, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_yd = bd_input_number_length.multiply(
          (bd_referance).divide(yd, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_mi = bd_input_number_length.multiply(
          (bd_referance).divide(mi, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      bd_nmi = bd_input_number_length.multiply(
          (bd_referance).divide(nmi, 4, RoundingMode.HALF_EVEN))
        .stripTrailingZeros();
      tv_result_nm.setText(bd_nm.toPlainString());
      tv_result_mm.setText(bd_mm.toPlainString());
      tv_result_cm.setText(bd_cm.toPlainString());
      tv_result_dm.setText(bd_dm.toPlainString());
      tv_result_m.setText(bd_m.toPlainString());
      tv_result_km.setText(bd_km.toPlainString());
      tv_result_in.setText(bd_in.toPlainString());
      tv_result_ft.setText(bd_ft.toPlainString());
      tv_result_yd.setText(bd_yd.toPlainString());
      tv_result_mi.setText(bd_mi.toPlainString());
      tv_result_nmi.setText(bd_nmi.toPlainString());
    }
  
    public void save(View view) {
      sharedpref_editor = sharedpref.edit();
      sharedpref_editor.putInt(STR_INPUT_UNIT_LENGTH,
        spr_unit_l.getSelectedItemPosition());
      sharedpref_editor.commit();
    }
  }
  </code></pre>
  
  <p>I've written it so the conversion between values happens automatically for the user as they type or change the item in the spinner i.e. no need for a "convert" button. I had originally used double to calculate numbers but sometimes that caused errors like 0.9999999999997 when it is supposed to show 1. After searching for solutions, I thought it best to use BigDecimal as they don't have these types of errors. Unfortunately, those types of errors still persist (eg. entering km=1 shows nm=999999999999.9999 instead of 1000000000000 but other conversions remain correct). Can anyone please point out what I am doing wrong?</p>