Problem with JavaScript arithmetic
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);
开发者_如何学JAVAmyfield.value = myval;
if(i < cur_idx)
{
document.getElementById("actual_"+i).innerHTML = myval;
}
}
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)
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.
精彩评论