0

I've got a simple table that allows users to enter 2 numbers, and then a script then calculates the annual average and gets the totals for all rows that have the same option in the select menu.

I've setup a sample JSFiddle:

http://jsfiddle.net/fmdataweb/73Jzc/1/

that shows how this works. I've just noticed that at times I get a strange rounding error (I want it to round to one decimal place). For example if you select "moderate" and then enter 5 and 4 for an average of 0.4, then click the button to create a new row and select "moderate" again then enter 3 and 40 for an average of 2.3 you'll notice the total for the moderate is "2.6999999999999997" when it should be 2.7.

If you enter other numbers it's fine so far in my testing but for some reason these combinations don't get rounded for the totals and I'm not sure why. Appreciate if anyone can point out the error in my script. Here's the script that does the averages and totals:

$('#nextYear')
    .on('change', 'select', calc)
    .on('keyup', 'input', calc);

function calc(){

    $('#nextYear tr:has(.risk)').each(function(i,v){

        var $cel = $(v.cells);

        var $risk = $cel.eq(1).find('option:selected').val();
        var $numb = $cel.eq(2).find('input').val();
        var $weeks = $cel.eq(3).find('input').val();
        var $avg = ($numb * $weeks) / 52;
        var $avgRounded = Math.round( $avg * 10 ) / 10;

        $cel.eq(4).find('input').val($avgRounded);

    });   

    var tot = {};

    $('#nextYear tr:has(.risk) option:selected')
                .map(function(i){
                    var el = $(this).val();
                    var qty = parseFloat($('#nextYear tr:has(.risk)').eq(i).find('td:last').prev().find('input').val());

                    if (!tot.hasOwnProperty(el)) {
                        tot[el] = 0;            
                    }
                    tot[el] += qty
                    return tot;
                }).get();

     // console.log(tot);
      $('#textfield6').val(tot.moderate);
     $('#textfield7').val( tot.high );

  }

user982124
  • 4,416
  • 16
  • 65
  • 140
  • 2
    This is not your code producing the problem, per se. It is a floating point problem with not being able to properly represent all numbers. I think this question might help you understand: http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem – TheZ Aug 15 '12 at 17:11
  • 1
    Why do so many of your variable names begin with `$`? Perfectly legal, but it's like you're having php envy. – awm Aug 15 '12 at 17:19

2 Answers2

3

Try $avg.toFixed(1); instead of Math.round( $avg * 10 ) / 10;

awm
  • 6,526
  • 25
  • 24
3

You problem is here:

$('#textfield6').val(tot.moderate);
$('#textfield7').val( tot.high );

You must round them like you did with

var $avgRounded = Math.round( $avg * 10 ) / 10;

or using .toFixed(1)

Edit:

Then, the code is:

$('#textfield6').val(tot.moderate.toFixed(1));
$('#textfield7').val(tot.high.toFixed(1));

You can see it here: http://jsfiddle.net/73Jzc/2/

Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Thanks Oriol - I'm a bit stumped with the syntax change required. Can you please let me know what the new syntax should be here? Thanks – user982124 Aug 15 '12 at 23:32
  • Thanks @Oriol - I was sure I tried that format but in any case it's working now. Thanks for your help. – user982124 Aug 16 '12 at 05:02
  • I've just noticed that implementing the new code to round the totals breaks the dynamic updating of the totals when you change the select menu option. I'm not sure why this would be but if you change one of the rows from moderate to high the sub totals don't dynamically update like the used to. Any ideas why? – user982124 Aug 16 '12 at 05:50
  • @user982124 That's because `tot.moderate` and `tot.high` are not always defined. Fixed in http://jsfiddle.net/73Jzc/6/ – Oriol Aug 16 '12 at 13:14