Coder Social home page Coder Social logo

Comments (13)

MikeMcl avatar MikeMcl commented on July 20, 2024

Yes, this is intended.

BigNumber.config(10) is the short form of BigNumber.config({ DECIMAL_PLACES: 10 }), which specifies that division is to be performed to 10 decimal places.

So, for example, 5e-15 / 3, which is 0.000000000000001666..., is 0 when rounded to 10 decimal places (assuming ROUND_HALF_UP rounding mode).

To do divisions on small values without losing precision just make sure that the DECIMAL_PLACES is set sufficiently high. For example, if you want 5e-15 / 3 to equal 1.666666667e-15 then it would need to be set to at least 24 (i.e 15 + 9).

Normally, you would just set a higher DECIMAL_PLACES value then just pass one less than the number of significant digits you want to toExponential, e.g.

BigNumber.config(30);
new BigNumber('5e-15').div('3').toExponential(9);    // '1.666666667e-15'

The ability to perform division to a specified number of significant digits, instead of decimal places, is a feature that will be added soon.

from bignumber.js.

josdejong avatar josdejong commented on July 20, 2024

Yes, this is intended.

Ai. I hope you are willing to change your mind on this. The number of decimals should really be independent from the exponent of a number.

I see similar issues with sqrt and pow: they seem not to reckon with the configured precision, resulting in numbers loosing digits or having too much digits.

The ability to perform division to a specified number of significant digits, instead of decimal places, is a feature that will be added soon.

Thanks, I'm looking forward to having this issue fixed!

from bignumber.js.

husayt avatar husayt commented on July 20, 2024

@MikeMcl Thanks for great library.

This whole problem with precision, decimal and exponential points is really tricky.
Maybe you can have a look at the lengthy discussion we had with @josdejong here. At the end we found a solution which allowed us to cover all possible cases. (Thanks @josdejong ) Also this is along with standard JS way of doing precisions and exponentials.

Users of our popular calculator at (http://numerics.info) have very different requirements and current settings allow them to meet whole spectrum of needs. That will work absolutely great, once we get bigNumber.js working.

from bignumber.js.

MikeMcl avatar MikeMcl commented on July 20, 2024

@josdejong

The number of decimals should really be independent from the exponent of a number.

I am not clear what you mean exactly, or why you believe that.

If a particular number of decimals (in exponential notation) is required then it can be specified as shown above. If a particular number of significant digits is required it can be specified by toPrecision.

I see similar issues with sqrt and pow: they seem not to reckon with the configured precision, resulting in numbers loosing digits or having too much digits.

The problem with statements such as this is that some viewers may mistakenly believe there is some fault with the library and that it is not working correctly. As I explained, and the README and documentation makes clear, the "configured precision" is in terms of decimal places (of a number in normal, non-exponential notation) not significant digits. sqrt and pow (negative exponents) always conform to the required precision in that sense, and numbers never lose or have too many digits.

I'm looking forward to having this issue fixed!

I don't think it's an issue that needs fixing, it's a fundamental design decision. Some people find it simpler to think in terms of decimal places, others in terms of significant digits. Maths homework sometimes required answers in terms of the former, sometimes the latter. Generally, perhaps more scientific use cases prefer significant digits and more financial use cases prefer decimal places. There are advantages and disadvantages to each.

The BigDecimal libraries work in terms of significant digits and there are quite complex rules as to the precision of the result of a calculation. I wanted to take a different, perhaps simpler approach: just one global decimal places setting for operations involving division, and other operations always returning full precision.

But, yes, it would be good to be able to specify precision in terms of significant digits and I am working on that at present as a by-product of adding support for non-integer powers.

Thanks for the feedback.

from bignumber.js.

josdejong avatar josdejong commented on July 20, 2024

I understand your point. However to me this is a serious flaw, not a feature.

What I would expect from a BigNumber library is to handle (a) very large numbers, (b) very small numbers, and (c) with an arbitrary (configurable) precision. Unfortunately bignumber.js only does (c) so far.

The design decision to handle precision like fixed point means that you effectively can't work with very small numbers, as you loose precision below DECIMAL_PLACES. And you can't efficiently work with very large numbers as all decimals are stored sort of as a fixed point number (new BigNumber('1e500').div(3) stores the number with 520 digits (!)). I would like BigNumber to work as a floating point number, storing a limited (configured) number of significant digits, independent from the exponent of the number. I don't think this would harm these "some people", as the can just set DECIMAL_PLACES very high and use .toFixed(xyz) to get output in their desired number-of-decimals-behind-the-point.

The following type of calculations should just be no problem for BigNumber with 20 digits, like it is no problem for a regular (floating point) Number with ~16 digits precision.

console.log(5e-30 / 3);                               // 1.6666666666666666e-30 
console.log(new BigNumber('5e-30').div(3).valueOf()); // 0

console.log(Math.sqrt(3e-30));                        // 1.7320508075688773e-15 
console.log(new BigNumber('3e-30').sqrt().valueOf()); // 0

from bignumber.js.

MikeMcl avatar MikeMcl commented on July 20, 2024

Those calculations are no problem for this library. It doesn't seem unreasonable to have to set the DP (decimal places) to 30 or 40 (depending on how many SD (significant digits) you want) when working with numbers such as 5e-30. The numbers are stored in floating point format so it is not inefficient to work with small numbers using a high DP.

What I would expect from a BigNumber library is to handle (a) very large numbers, (b) very small numbers, and (c) with an arbitrary (configurable) precision. Unfortunately bignumber.js only does (c) so far.

Well, it does all three, but clearly not as you would like.

The design decision to handle precision like fixed point means that you effectively can't work with very small numbers, as you loose precision below DECIMAL_PLACES.

Yes, but only in the same way that you can lose precision when performing division to an arbitrary number of SD if you set the value too low

precision = 10 (significant digits)
1e+30 / 3 = 333333333300000000000000000000    // Incorrect by more than 33333333333333333333

decimal places = 10
1e+30 / 3 = 333333333333333333333333333333.3333333333

As shown, it is easier to lose precision with large numbers when it is specified in terms of SD, and as larger numbers are arguably more commonly used than extremely small numbers, it follows that it is easier to avoid losing precision using DP than SD.

And you can't efficiently work with very large numbers as all decimals are stored sort of as a fixed point number (new BigNumber('1e500').div(3) stores the number with 520 digits (!)).

Yes, but 1e500 is not just a big number, it is an enormous number (for example, the estimated number of atoms in the universe is 1e+80).

And if you want to store and use fewer SD you can do

new BigNumber( BigNumber('1e500').div(3).toPrecision(20) )

although I accept that this is inefficient and that is why I'm adding better support for SD.

As it is, this library is best used for numbers of a few hundred digits and less, and perhaps when decimal places are more important than significant digits (as in, for example, financial calculations). The priority is not to be able to efficiently handle enormous/tiny values that most users of the library will not be using.

from bignumber.js.

josdejong avatar josdejong commented on July 20, 2024

This is indeed the best choice for financial calculations and less for scientific calculations. Reading the docs, the setting DECIMAL_PLACES is only applied by div, sqrt, and pow, so they are the only ones who can suffer loosing precision. Maybe you can introduce a complementary setting like MINIMUM_SIGNIFICANT_DIGITS to prevent that :D.

Anyway, I agree with you that this is kind of an edge case. I'm looking forward to your improvements for division (and sqrt, pow as well?). Thanks for this excellent and well documented library.

from bignumber.js.

MikeMcl avatar MikeMcl commented on July 20, 2024

Hi Jos,
I have just published decimal.js which handles precision in terms of significant digits. It was going to be an update to bignumber.js, but I made so many changes I thought I better release it as a new library.

from bignumber.js.

josdejong avatar josdejong commented on July 20, 2024

That's awesome Michael! I'm going to check it out asap.

from bignumber.js.

ruimarinho avatar ruimarinho commented on July 20, 2024

@MikeMcl does this explain why new BigNumber('1.1').dividedBy('2').times(new BigNumber(2).dividedBy('1.1')).toString() returns 1.000000000000000000001 and not 1?

from bignumber.js.

MikeMcl avatar MikeMcl commented on July 20, 2024

2 / 1.1 has a non-terminating decimal expansion (an infinite number of digits after the decimal point), which means that the result of BigNumber(2).dividedBy(1.1) will only be an approximation.

BigNumber.config().DECIMAL_PLACES   // 20
BigNumber.config().ROUNDING_MODE    // 4
new BigNumber(2).dividedBy(1.1)     // 1.81818181818181818182

BigNumbers are stored as floating-point values not ratios.

from bignumber.js.

ruimarinho avatar ruimarinho commented on July 20, 2024

Ok, so because BigNumbers are stored as floating-point and not ratios, then the lib is unable to cancel the ratios and return exactly 1, correct? In that case, should the number of DECIMAL_PLACES be increased in order to cover the necessary precision? Is this what decimal.js does? (edit: reading about it here - MikeMcl/big.js#45)

from bignumber.js.

MikeMcl avatar MikeMcl commented on July 20, 2024

Infinite precision would be needed in order to return exactly 1.

decimal.js works using significant digits instead of decimal places, but it also stores numbers in a floating-point format.

Your choices would seem to be to either find a library that stores numbers as ratios or just round the result.

a = new BigNumber(1.1).dividedBy(2)
b = new BigNumber(2).dividedBy(1.1)
a.times(b).round()      // 1
a.times(b).round(10)    // 1
a.times(b).round(19)    // 1
a.times(b).round(20)    // 1
a.times(b).round(21)    // 1.000000000000000000001

from bignumber.js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.