1

I have a form for my customers to add budget projections. A prominent user wants to be able to show dollar values in either dollars, Kila-dollars or Mega-dollars.

I'm trying to achieve this with a group of radio buttons that call the following JavaScript function, but am having problems with rounding that make the results look pretty crummy.

Any advice would be much appreciated!

Lynn

function setDollars(new_mode)
 {
  var factor;
  var myfield;
  var myval;

  var cur_mode = document.proj_form.cur_dollars.value;

  if(cur_mode == new_mode)
   {
    return;
   }
  else if((cur_mode == 'd')&&(new_mode == 'kd'))
   {
     factor = "0.001";
   }
  else if((cur_mode == 'd')&&(new_mode == 'md'))
   {
     factor = "0.000001";
   }
  else if((cur_mode == 'kd')&&(new_mode == 'd'))
   {
     factor = "1000";
   }
  else if((cur_mode == 'kd')&&(new_mode == 'md'))
   {
     factor = "0.001";
   }
  else if((cur_mode == 'md')&&(new_mode == 'kd'))
   {
     factor = "1000";
   }
  else if((cur_mode == 'md')&&(new_mode == 'd'))
   {
     factor = "1000000";
   }

  document.proj_form.cur_dollars.value = new_mode;

  var cur_idx = document.proj_form.cur_idx.value;
  var available_slots = 13 - cur_idx;
  var td_name;
  var cell;
  var new_value;

  //Adjust dollar values for projections
  for(i=1;i<13;i++)
   {
    var myfield =  eval('document.proj_form.proj_'+i);
    if(myfield.value == '')
     {
      myfield.value = 0;
     }
    var myval = parseFloat(myfield.value) * parseFloat(factor);
    myfield.value = myval;
    if(i < cur_idx)
     {
      document.getElementById("actual_"+i).innerHTML = myval;
   }
 }
4
  • Erm, what's the problem? Commented Jun 2, 2010 at 22:24
  • @BlueRaja: I can tell you haven't used javascript floats. It's pretty common to have 2.10 + 5.15 = 7.249999999999999999999999999999999999999. Pretty humiliating. I once did a website that sold a ad that charged by the word, and somehow .10 cents times 200 words would equal 19.999999999999999999 dollars. Commented Jun 2, 2010 at 22:31
  • Probably FP rounding. .000001 isn't exactly .000001, and occasionally you'll get results like 450.2500001 where you wanted 450.25. Commented Jun 2, 2010 at 22:34
  • 2
    Two things you should avoid: using floats for monetary values and converting values back and forth. Store the actual values in dollars (or in cents, if appropriate) as ints and only format those values for display. If those form fields are supposed to be editable in a chosen format, you'll have to store the actual value in dollars elsewhere, like a structure in javascript or a hidden input in your html. Also, please don't use eval: var myfield = document.proj_form['proj_'+i]; should work just fine. Commented Jun 2, 2010 at 22:35

2 Answers 2

3

First of all, Don't set myfield.value = myval after doing the math. You'll accumulate rounding errors with each additional selection of one of the radio buttons. Keep myfield.value as dollars all the time, then calculate a display value. This will also reduce the number of cases in your if-else cascade, as you will always be converting from dollars.

Now calculate by division -- you'll never have to multiply by 0.001 or 1000 since you're always converting in the same direction.

Use Math.round() to control rounding errors. You can multiply your original value first, then divide by a larger factor to also help control rounding errors; e.g. both these are the same in pure mathematics:

newvalue = value / 1000;
newvalue = (value * 10) / 10000;

Added

switch (new_mode)
{
    case 'd':
        divisor = 1;
        break;
    case 'kd':
        divisor = 1000;
        break;
    case 'md':
        divisor = 1000000;
        break;
}
var displayValue = myfield.value / divisor;

Also, don't assign a string of numbers divisor = "1000"; use actual numbers divisor = 1000 (without the quotes)

Sign up to request clarification or add additional context in comments.

Comments

1

Javascript's floating point numbers are a constant source of irritation.

You should try adding toFixed() to reduce the inevitable absurd decimals, and I've actually had to resort to forcing it to do it's rounding down where I don't care about it by doing something like:

   number_to_be_rounded = Math.round(number_to_be_rounded*1000)/1000;
   number_to_be_rounded = parseFloat(number_to_be_rounded.toFixed(2));

It's ugly, but it's close enough for a non-financial system.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.