0

I have an interesting problem that I would like to share with you all. On a form we have repeating rows with percent allocation. In the end all the rows combined need to equal 100.000 (or 100%). If it does then it passes validation and the form can be submitted. It is a requirement that we go out 3 decimal points.

But with the following combination the form fails to meet validation. It is really odd.

  • Row 1: 63.877
  • Row 2: 34.286
  • Row 3: 1.837
  • Total = 100.000

HTML

<!-- Repeating Field in Rows -->
<input type="text" name="txtDistributionPerc" id="txtDistributionPerc" 
onkeypress='return chkKeys(event, "C");' maxlength="7" 
onblur="txt_blur_calculateFundingTotal(this);"></input>

JavaScript JQuery

// Filters out invalid keystrokes
function chkKeys(e,type){
    var keynum = e.keyCode;
    var keychar = String.fromCharCode(keynum);

    switch (type){
        case 'C':   /* currency ($, numbers, .) */
            valChk = /[0-9\$\.]/;
            return valChk.test(keychar);
            break;
        default:
            break;
    }
}

//Calculates a specific one based on the element passed
function txt_blur_calculateFundingTotal(ele)
{
    if(ele)
    {
        var total = 0.000;
        $(ele).closest('table').find('input[name=txtDistributionPerc]').each(function (i) {
            this.value = formatCurrency(this.value, 3, '.', '');
            var tmp = parseNumber(this.value);
            if(tmp < 0.000 || tmp > 100.000) { 
                this.value = '0.000'; 
                tmp = 0.000;
            }
            total+=tmp;
        });
        $(ele).closest('table').find('input[name=txtTotalPerc]').val(formatCurrency(total, 3, '.', ''));
        if(total != 100.000 && total != 0.000)
        {
            $(ele).closest('table').find('input[name=txtTotalPerc]').addClass('error');
            $(ele).closest('table').find('input[name=txtTotalPercValidated]').val('');
        }
        else
        {
            $(ele).closest('table').find('input[name=txtTotalPerc]').removeClass('error');
            $(ele).closest('table').find('input[name=txtTotalPercValidated]').val('true');
        }
    }
}

Is there a better way to do this? Thanks for looking.

Mystified
  • 3
  • 1
  • 2
  • what is the value you get if you do a console.log(total); after the .each is done? does it equal 100? I'm asking because I'm wondering if the addition is not working (rounding error) or the if check is not working right – MikeScott8 Jan 28 '14 at 16:32
  • What's the source of `formatCurrency`? – Philipp Gayret Jan 28 '14 at 16:35
  • 3
    That's how computers work. Floating point numbers are base 2 amounts with limited precision that don't necessarily map to base 10 numbers. – Álvaro González Jan 28 '14 at 16:36
  • `console.log(63.877 + 34.286 + 1.837); // 100.00000000000001` – Anthony Grist Jan 28 '14 at 16:40
  • You are mixing numbers and strings-there are no trailing zeroes after a decimal point of a number. To work to a precision of three decimal points, use Math.round((n*1000)/1000)). – kennebec Jan 28 '14 at 18:05
  • Thanks everyone we are getting really close. I added : var tmp = Math.round((tmp1 * 1000) / 1000); and this validates now but it will also validate 100.1 really close! – Mystified Jan 28 '14 at 19:47
  • Have a look at http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem Maybe it helps you – Premshankar Tiwari Jan 29 '14 at 07:39
  • Does this answer your question? [How to deal with floating point number precision in JavaScript?](https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript) – Aaron Morefield Dec 27 '21 at 03:53

1 Answers1

0

Multiply the values by 1000 and work with integers.

It seems it has to be with float values.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
agastalver
  • 1,036
  • 8
  • 13