MikeMcl / decimal.js

An arbitrary-precision Decimal type for JavaScript
http://mikemcl.github.io/decimal.js
MIT License
6.35k stars 480 forks source link

some cases normal operations still accurate than decimal.js #213

Closed tarikjabiri closed 1 year ago

tarikjabiri commented 1 year ago

Hi,

const angle = 3 * Math.PI / 2
const degrees = angle * 180.0 / Math.PI // 270
const degreesUsingDecimal = new Decimal(angle).div(Math.PI).mul(180).toNumber() // 270.00000000000006

I am not sure if this an expected value or not.

Regards

MikeMcl commented 1 year ago

The Decimal version is more accurate.

If you reduce the precision you will get your expected result.

Decimal.precision = 16;
tarikjabiri commented 1 year ago

I did set the precision to 16, but the other tests are failed

If this accurate I will go with this value as expected, its not something bad its very small, I just want to make sure this is not a bug.

regards

josdejong commented 1 year ago

These rounding errors are in the nature of floating point numbers, it is not a bug.

In general, if you use more digits you'll get round-off errors less often. But still, if you work with irrational numbers like pi, you're always dealing with an approximate representation, and round-off errors can pop up when operating with approximated values. You can read more about it here: https://en.wikipedia.org/wiki/Floating-point_arithmetic#Representable_numbers,_conversion_and_rounding

In your example you're even mixing regular numbers (angle, Math.PI) having a precision of about 16 digits and are an approximation. and you turn these into a Decimal (which has by default 20 digits). If you do it purely with higher precision Decimals, you get:

const pi = Decimal.acos(-1)
const angle = new Decimal(3).mul(pi).div(2)
const degreesUsingDecimal = angle.div(pi).mul(180)
console.log(degreesUsingDecimal.toString()) // 270
tarikjabiri commented 1 year ago

Yeah the problem was PI, Thank you, this Decimal.acos(-1) is a good hack 👍