Js causes and solutions in precision problems toFixed

toFixed () method Number rounded to the specified number of decimal digits. For example, data Num 2 decimal places, it is expressed as: toFixed (Num); however different rules of rounding rules and mathematics, using banker's rounding rule, banker's rounding: the so-called rounding Banker its essence is a four-round banker to take even (also called banker's rounding stay double) method. Specific rules are as follows: simple terms is: banker's rounding consider, after five went into a non-zero, zero parity look after five before five to even be discarded, before five to get into a surprising.

Testing has been found in chorme below, does not fully comply with this rule, especially not behind the numbers 5, when the judgment is not so, as follows:

var b = 1.335

b.toFixed(2)

"1.33"

var b = 1.345

b.toFixed(2)

"1.34"

var b = 1.355

b.toFixed(2)

"1.35"

var b = 1.365

b.toFixed(2)

"1.36"

var b = 1.375

b.toFixed(2)

"1.38"

var b = 1.385

b.toFixed(2)

"1.39"

 

We can not completely found in chorme to follow this rule, if it has its own algorithm, but after all, it does not follow a common algorithm bankers, so tofixed this method is less money in relation to the calculation of business.

All in all: whether to introduce toFixed solve the problem Hao precision floating-point computations missing, it does not use bankers rounding worth mentioning, it is to solve the problem of accuracy, but it can not do without binary floating point environment, but at least he helped we found the problem, so that we have a solution.

 

A way to start is to be rounded after a judge alone carry out alone.

Solution:

By rewriting toFixed method:

Number.prototype.toFixed = function (n) {

let result = number.toString();

const arr = result.split('.');

const integer = arr[0];

const decimal = arr[1];

result = integer + '.' + decimal.substr(0, n);

const last = decimal.substr(n, 1);

 

// rounded to an integer reprocessing, to avoid loss of precision floating point number

if (parseInt(last, 10) >= 5) {

const x = Math.pow(10, n);

result = ((parseFloat(result) * x) + 1) / x;

result = result.toFixed(n);

}

return result;

}

 

Then find accuracy problems caused by computer binary coding, detailed in a blog on.

Own debugger, found the page js into an infinite loop. Obviously the problem lies in the callback in toFixed toFixed, the results did not come out, continue debugger, there has been a startling discovery. The following is a console test:

console.log(2.115 * 100) // 211.50000000000003

console.log(2.0115 * 1000) // 2011.4999999999998

 

Now that you've been into the circulation, I'll pull you out manually.

result = (Math.round((parseFloat(result)) * x) + 1) / x;

 

The final complete method of rewriting toFixed

// toFixed compatible method

Number.prototype.toFixed = function (n) {

    if (n > 20 || n < 0) {

        throw new RangeError('toFixed() digits argument must be between 0 and 20');

    }

    const number = this;

    if (isNaN(number) || number >= Math.pow(10, 21)) {

        return number.toString();

    }

    if (typeof (n) == 'undefined' || n == 0) {

        return (Math.round(number)).toString();

    }

 

    let result = number.toString();

    const arr = result.split('.');

 

    // integers case

    if (arr.length < 2) {

        result += '.';

        for (let i = 0; i < n; i += 1) {

            result += '0';

        }

        return result;

    }

 

    const integer = arr[0];

    const decimal = arr[1];

    if (decimal.length == n) {

        return result;

    }

    if (decimal.length < n) {

        for (let i = 0; i < n - decimal.length; i += 1) {

            result += '0';

        }

        return result;

    }

    result = integer + '.' + decimal.substr(0, n);

    const last = decimal.substr(n, 1);

 

    // rounded to an integer reprocessing, to avoid loss of precision floating point number

    if (parseInt(last, 10) >= 5) {

        const x = Math.pow(10, n);

        result = (Math.round((parseFloat(result) * x)) + 1) / x;

        result = result.toFixed(n);

    }

    return result;

}

 

Guess you like

Origin www.cnblogs.com/ranyonsue/p/11388281.html