Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid values for math.round #316

Closed
tusharmath opened this issue Apr 3, 2015 · 7 comments
Closed

Invalid values for math.round #316

tusharmath opened this issue Apr 3, 2015 · 7 comments
Labels

Comments

@tusharmath
Copy link

math.round(2.135, 2) // returns 2.13 when it should be 2.14

@josdejong josdejong added the bug label Apr 4, 2015
@josdejong
Copy link
Owner

Thanks, will fix it asap.

@josdejong
Copy link
Owner

While the direct cause was because of rounding issues in the round implementation of math.js, it turns out JavaScript itself has these issues itself too:

(0.25).toFixed(1); // 0.3
(0.15).toFixed(1); // 0.1 oops!

Let's see what we can do about it...

@Yaffle
Copy link
Contributor

Yaffle commented Apr 6, 2015

JavaScript uses binary floating point, so 2.135 === 2.13499999999999978684

@josdejong
Copy link
Owner

exactly...

@tusharmath
Copy link
Author

I have faced the issue myself, so I created this custom Class to make it work.

function Decimal(val) {
    var dotPosition, sVal;
    if (val instanceof Decimal) {
        this.p = val.p, this.m = val.m;
    } else {
        sVal = Number(val).toString();
        this.p = 0, this.m = parseInt(sVal.replace('.', ''), 10);
        dotPosition = sVal.indexOf('.');
        if (dotPosition !== -1) {
            this.p = sVal.length - dotPosition - 1;
        }
    }
}
Decimal.prototype.valueOf = function () {
    return this.m / Math.pow(10, this.p);
};

Decimal.prototype.mul = function (val) {
    var a = new Decimal(this),
        d = new Decimal(val);
    a.p += d.p;
    a.m *= d.m;
    return a;
};

Decimal.prototype.toFixed = function (precision) {
    var a, radix;
    a = new Decimal(this);
    radix = Math.pow(10, a.p - precision);
    a.m = Math.round(a.m / radix);
    a.p = precision;
    return a;
};
var r = new Decimal(2.135);
console.log(2.135.toFixed(2), r.toFixed(2).valueOf()); //Outputs: 2.13 2.14

@Yaffle
Copy link
Contributor

Yaffle commented Apr 6, 2015

you can use big number (used by mathjs) for decimal arithmetic, and, possibly, you can avoid interpreting js numbers as "decimal fractions" fully if you use decimal arithmetic everywhere.

@josdejong
Copy link
Owner

We should indeed not rely on JavaScripts built in functions toFixed, toExponential, toPrecision. I've now created a little class NumberFormatter which does not use JavaScript's functions but reads a value a string and handle the digits individually.

We could indeed use the functionality from decimal.js for formatting. I think though that it's important to keep these low-level number functions independend of decimal.js. In math.js v2 we want to be able to create custom builds of math.js, for example with big numbers excluded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants