How to manage numbers with x.999999 decimal places - javascript

I'm facing the next problem.
I am performing mathematical operations to calculate weights where I am using a function to return only 2 decimal places but sometimes the result is not as expected. Here is an example
I have a paper that weighs 49.8 and I want to subtract 1/4, that is 12.45 and do it 4 times but when I do this subtraction 49.8 - 12.45 the result gives me 37.34999999999999999999994 when in fact it should be 37.35 because if I do the whole process with my function the result would not be 0, it would be as follows
49.8 - 12.45 = 37.34
37.34 - 12.45 = 24.89
24.89 - 12.45 = 12.44
And you can't 12.44 - 12.45
So that's the problem because 49.8/4 = 12.45 but the way I'm doing it is not possible
How can I solve this, a way where if the third decimal place of the number is 9 round it and return it with only 2 decimals otherwise use my function to return it with 2 decimals
My function:
function threeDecimals(num) {
const multipliedNum = num * 100;
const truncatedNum = Math.trunc(multipliedNum);
const num3decimals = truncatedNum / 100;
return num3decimals;
}

Floating point numbers have this property by design. If you need to have base-10 precision, it's not enough to add a few decimals and round, because errors can still slip in in higher precisions.
You will need to use a third party library that guarantees base10 accuracy for the examples you gave.
Note that nothing will give you accuracy for every type of operation. Even Decimal.js will round 1/3 and not have a perfect representation, just like floating point numbers give seemingly 'incorrect' outcomes.

If you need exact calculations, operate on smaller units (milligrams instead of grams), so that intermediate values are always integers:
weight = 49800
f = (weight / 4) | 0
weight -= f
weight -= f
weight -= f
result = weight / 1000
console.log(result)

Related

Javascript (Floating-Point Question): is there any reliable way to convert a fraction to a decimal AND THEN BACK AGAIN?

Say I have a very simple fraction (for the purposes of this question, presuppose all cases discussed will be 0 < [VALUE] < 1; that is: nothing like 8 7/16 or 1.625):
My starting fraction:
someFraction = '1/3'; // result: STRING value containing "1/3".
Okay easy enough to convert that to a decimal:
correspondingDecimal = eval(someFraction); // result: FLOAT value containing 0.3333333333333333
(yes, yes, "evils of eval and all that. Work with me here; this is an example)
Now say I wanted it BACK again to "1/3". If this were 1/4 (0.25), no problem:
We'd want a simple greatest common denominator function (to reduce the results to manageability), say
function reduce(numerator,denominator){
let getGCD = (a,b) => b ? getGCD(b, a%b) : a;
gcd = getGCD(numerator,denominator);
return (numerator/gcd) + '/' + (denominator/gcd);
}
...and then we can just grab out the decimal portion of our test string:
let justDecimalPart = ('' + 0.25).slice(2);
and multiply by its length power to get our numerator and our denominator to reduce:
let commonFactor = Math.pow(10,justDecimalPart.length); // Result: 100
// = 25 = 100
reduce((justDecimalPart * commonFactor), commonFactor); // Result: 1/4
... capital! That worked out fine!
EDIT: On a whim, I tried that same reduce function on the decimal values without multiplying them at all (reduce(0.25,1); // result: "1/4"). Sorry; brain-fart. Ignore the exponent bit above ☺️
...But 1/3 is a repeating decimal. If we run the same steps through, we wind up with 3333333333333333/10000000000000000 (((1/3) * 1e16) + '/' + 1e16). It's even worse with something like 17/29.
Is there any way to arrive BACK at "1/3" after taking the plunge from 1/3?
EDIT: I'm not trying to get to an infinite precision, just to a manageable one, preferably through throttling/limiting decimal lengths and then rounding/simplifying the result.
Use-case example here: I'm working on a carpentry calculator. 25mm, expressed in US Common units (to a precision of 3 decimal places) is identical to 63/64. I can only seem to arrive at 125/128.
(25/25.4).toPrecision(3) = 0.984
(63/64).toPrecision(3) = 0.984
It appears I was leaving out a step in my conversion; I wasn't rounding the result of the decimal multiplied against the denominator:
decimalValue = (63 / 64).toPrecision(3); // Result: 0.984
denominator = 128;
numerator = decimalValue * denominator; // Result: 125.952
numerator = Math.round(numerator); // Result: 126
reduce(numerator, denominator); // Result: 63/64

How to cut two digits after my float? In Java script without changing to string

I want to take 2 digits after float like below example:
function cut() {
var num1=8.844
// should be return 8.84
var num2=8.847
// should be return 8.84
}
You could multiply the value with 100, take the floorished value and divide by 100.
You may witness the wonderful world of floating point arithmetic, where numbers have some more or less decimals, like Is floating point math broken?
function cut(value) {
return Math.floor(value * 100) / 100;
}
console.log(cut(8.844));
console.log(cut(8.847));

Can I accurately calculate an average from a medium size set of 2 d.p. numbers using JavaScript?

I need to find the average of a set of values and after doing some reading am not sure if JavaScript is able to produce an accurate result or not.
Each value has a precision of 2 d.p. and there could be up to 10000 of them between -100000.00 and 100000.00. The result also needs to be to 2 d.p.
From what I can see it is usually the figures around the 16th decimal place that are inaccurate which means that I would have to average an extremely large set before affecting my result. Is the best way of doing it to simply sum all of the values, divide by the total number and then use a toFixed(2)?
You could take advantage of your 2dp prevision, and multiply all your numbers by 100 first, then do the mathematics using integers. EG, a float error occurs in this simple average (I am just using 1dp for this example):
(0.1 + 0.2) / 2
0.15000000000000002
But this works:
(0.1*10 + 0.2*10) / (2*10)
0.15
Some good reading here:
http://floating-point-gui.de/basic/
and here:
How to deal with floating point number precision in JavaScript?
and a really precise fix to do it using decimals is to use this:
https://github.com/dtrebbien/BigDecimal.js
Example for 2 dp:
var numbers = [0.10, 0.20, 0.30]
var simple_average = numbers.reduce(function(a, b) {
return a + b
}) / numbers.length
console.log(simple_average)
var smart_average = numbers.map(function(a) {
return a * 100
}).reduce(function(a, b) {
return a + b
}) / (numbers.length * 100)
console.log(smart_average)
This demo can be run here -- http://repl.it/e1B/1

Rounding elements of a formula up/down until the result is an integer

I want to round up or down a until the result is an integer.
a = 1.2
b = 1.5
a*b*16 = 28.8
However, I have a criterion: a must be fixed to no more than 3 decimal places. So I need a calculation where the above example would output to this:
a = 1.25
b = 1.5
a*b*16 = 30
I'm actually coding something in Sass, but if anyone could point me in the right direction, whether it be written in JavaScript or whatever. I just need help formulating this confusing calculation!
Criteria:
a must have no more than 3 decimal places.
the result must be an integer.
Is this even possible?
You cannot guarantee that the result will be an integer if you limit the precision of the variables, no matter what method you use.
Examples:
If b = 3, then a = 30 / (16 × 3) = 30/48 = 5/8 = 0.625
In this case, 0.625 × 3 × 16 = 30 exactly.
If b = 7, then a = 30 / (16 × 7) = 30/112 = 15/56 = 0.267857...
Rounding a results in 0.268, and 0.268 × 7 × 16 = 30.016, which is the closest you can come to 30. In other words, there is no value of a that will satisfy onthe criteria, and 0.268 is the best you can do.
But you can solve for the best value to make the result as close as possible to an integer.
Solve the equation for the desired variable, then round to the appropriate number of decimals.
a = 30. / (16. * b); // true value
a = ((int) (1000 * a + 0.5)) / 1000; // round to 3 decimals
Most modern languages provide library functions to do the rounding for you; I wrote it "long-hand" so you can understand how it works.
i = Math.round(a*b*16);
a = i/b/16;
a = a.toFixed(2);
b = i/16/a;
test om i==a*b*16

How to use division in JavaScript

I want to divide a number in JavaScript and it would return a decimal value.
For example: 737/1070 - I want JavaScript to return 0.68; however it keeps rounding it off and return it as 0.
How do I set it to return me either two decimals place or the full results?
Make one of those numbers a float.
737/parseFloat(1070)
or a bit faster:
737*1.0/1070
convert to 2 decimal places
Math.round(737 * 100.0 / 1070) / 100
(737/1070).toFixed(2); rounds the result to 2 decimals and returns it as a string. In this case the rounded result is 0.69 by the way, not 0.68. If you need a real float rounded to 2 decimals from your division, use parseFloat((737/1070).toFixed(2))
See also
Also you can to use [.toPrecision(n)], where n is (total) the number of digits. So (23.467543).toPrecision(4) => 23.47 or (1241876.2341).toPrecision(8) => 1241876.2.
See MDN
Try this
let ans = 737/1070;
console.log(ans.toFixed(2));
toFixed() function will do
to get it to 2 decimal places you can: alert( Math.round( 737 / 1070 * 100) / 100 )
with lodash:
const _ = require("lodash");
Use of _.divide() method
let gfg = _.divide(12, 5);
Printing the output
console.log(gfg)
2.4
credit

Categories

Resources