Difference in Rounding between Android App and Javascript code - javascript

I get two different results when attempting to calculate and round these numbers. The today number is 336887 and the yesterday number is 336582. I had a similar issue with another field, but after updating the Java code the discrepancy disappeared.
Javascript Code:
document.getElementById("txt1").value = ((today - yesterday) / 10000).toFixed(3);
Android Code:
public Double RoundDouble(Double num, Integer places)
{
Double temp = Math.pow(10.0, places);
num = num * temp;
Math.round(num);
num = num / temp;
return num;
}
Double total = RoundDouble((today - yesterday) / 10000,3);
txt1.setText(df.format(total ));
The Javascript code returns .031 while the Android code returns .030. I did the Math and before rounding, the number is .0305. I'm unsure what is causing this issue as the other field I had the issue with rounds .0295 to .030 properly.

The fraction ((336887 - 336582) / 10000) is not representable as an IEEE-754 double precision number. If you try ((336887 - 336582) / 10000).toFixed(20) you'll get 0.03049999999999999933.
The reason for the difference in the Android version could be the way you handle the return of Math.round(num): you ignore it. You might find it more useful to change the line to num = Math.round(num);.
It is also possible to change the rounding mode in Android. The default rounding mode in ECMAScript is nearest-to-even which is HALF_EVEN in Android.

Related

karatsuba multiplcation of large numbers fails in javascript

I've tried two versions of a karatsuba multiplcation algorithm and they both fail with different results when I test them with large X and Y values.
The parameters I'm using
const x = 3141592653589793238462643383279502884197169399375105820974944592
const y = 2718281828459045235360287471352662497757247093699959574966967627
const solution = 8539734222673567065463550869546574495034888535765114961879601127067743044893204848617875072216249073013374895871952806582723184
Algorithm1 I got from this page: https://gist.github.com/haocong/c2d9b2169d28eb15a94d
Expected value to equal:
8.539734222673567e+126
Received:
7.292575034127423e+22
Algorithm2 I got from this page: https://stackoverflow.com/a/28376023/604950
Expected value to equal:
8.539734222673567e+126
Received:
6.0002556749374185e+22
To reproduce you can grab this PR:
https://github.com/Falieson/Algorithms-Illuminated-Part1_TheBasics/pull/1
That is because you are using numbers that are too big and JavaScript doesn't know how to handle them.
The Number.isSafeInteger() method determines whether the provided value is a number that is a safe integer.
2^53 - 1 is a safe integer: it can be exactly represented, and no other integer rounds to it under any IEEE-754 rounding mode. In contrast, 2^53 is not a safe integer.
console.log(warn(Math.pow(2, 53)));
// expected output: "Precision may be lost!"
MDN
e.g. in your second algorithm you are doing
var res = (z2 * Math.pow(10, 2 * m ) ) + ( (z1-z2-z0) * Math.pow(10, m )) + z0;
which is not a safe operation in your case and JavaScript fails to compute it properly, giving you a wrong result.
If you put this code under the above mentioned line, you will see that.
console.log(Number.isSafeInteger(10 ** (2 * m)));
This evaluates to false.

New to JavaScript; Trying to Understand Why My Loop Isn't Running Properly When I Plugin Different Values

I am new to coding/JavaScript and I'm trying to understand why one of my loops refuses to run as I intended.
Basically, I am setting a loop that only outputs a certain part (fraction) of 100. As you can see in the snapshot, everything works fine when I am outputting quarters. However, when I attempt to output tenths, the loop stops after two-tenths, when it should output ten-tenths.
Both loops are exactly the same, syntax wise. Would anyone mind explaining why one runs, while the other doesn't? Thanks in advance!
var quarter = .25;
for (x = 1; x <=100; x++)
{
if (x / 100 === quarter)
{
console.log (x + " is one of the quarter");
quarter = quarter + .25;
}
}
console.log (" ");
var part = .1;
for (x = 1; x <=100; x++)
{
if (x / 100 === part)
{
console.log (x + " is one of the part");
part = part + .1;
}
}
Snapshot of Editor + Terminal with Code in Question
Try this code out:
code
var part=0.1;
for(x=1;x<=100;x++){
if(x/100===part){
console.log(x);
part=parseFloat((part+.1).toFixed(1));
}
}
The problem is 0.1+0.1+0.1= 0.300000004 in javascript which can be fixed using the above code
The reason is JS not good at floating point addition, and it will not output what you noramlly will expect
> console.log(0.2+.1)
> 0.30000000000000004
Copied from another stackoverflow(Weird Javascript Behaviour: Floating Point Addition giving the wrong answer)
It has to do with how decimal values are converted to binary floating point numbers. 1/10 turns into a repeating decimal in binary, so the number is not perfectly represented, and repeated operations can expose the error.
JavaScript uses IEEE-754 floating point numbers, for the record. Some other languages have the same problem.
checkout this also:
Is floating point math broken?

Getting input to round to integer value if result decimal is followed by a series of 9s

I have a JavaScript calculator which uses the Math.cbrt() function. When I calculate the cube root of 125 it returns 4.999999999999999. I understand that I could use Math.round() to round any answers that this function returns to integer values, but I do not want to do that exactly. Is there a way to use this if and only if the result of calculation is some number followed by a string of 9s (or something similar like 4.99999998 perhaps) after the decimal?
What you are dealing with is the frustration of floating point numbers in computing. See the Floating Point Guide for more information on this critical topic.
The short version:
Certain non-integer values cannot be represented accurately by computers, so they store a value that is "near enough". Just try evaluating 3.3 / 3 in your favourite REPL.
Say what?!
Computers are supposed to be perfect at this numbers/math thing, right? Can I trust any answer they give me?
Yes, for integers, they are pretty much perfect. But for non-integer calculations, you should assume that answers won't be exact, and account for these floating point errors.
The solution in Javascript
In newer versions of Javascript, you have a defined constant Number.EPSILON, which is the smallest difference between the actual number and the approximation that it can actually store.
Using this, you can multiply that constant by the result you get and add it to the result and you should get the exact value you require.
function cbrt(n) {
return Math.cbrt(n) + (Number.EPSILON * Math.cbrt(n));
}
Alternatively, you can use the rounding behaviour of the .toFixed() method on numbers together with the parseFloat() function if you only care about numbers up to a certain number of decimal places (less than 20).
function num(n, prec) {
if (prec === void 0) prec = 8; // default to 8 decimal places
return parseFloat(n.toFixed(prec));
}
var threshold = 0.999; // set to whatever you want
var fraction = result % 1;
if (fraction >= threshold) {
result = Math.round(result);
}

Math.flooring a scientific notation at a certain decimal

I am trying to Math.floor a scientific notation, but at one point the number gets too big and my current method doesn't work anymore. This is what I am using atm
var nr = (number+"").length - 4;
if( nr > 1 ) {
nr = Math.pow( 10, nr );
number= Math.floor(number/nr)*nr;
number= number.toExponential(3);
}
When it becomes a scientific notation by default, I think that's e20+, than my .length method doesn't work anymore since the length it returns isn't accurate. I can think of a work around, and that's to find out the number after e, and update my nr to Math.floor it properly, but it seems like so much work to do something so simple. Here's an example number 8.420960987929105e+79 I want to turn this into 8.420e+79, is there a way I can Math.floor the third decimal point always, no matter what the number is? As it stands when I use toExponential(3) it always rounds the number. My numbers can get as high as e+200 easily, so I need an easier way of doing what I'm currently doing.
Edit: managed to find a work around that works besides Connor Peet's answer for anyone who wants extra options
var nr = 8.420960987929105e+79+"";
var nr1 = nr.substr(0,4);
var nr2 = nr.substr(4, nr.length);
var finalNr = Number(nr1 + 0 + nr2).toExponential(3);
This way is more of a hack, it adds a 0 after the 4th number so when toExponential rounds it up, it gets 'floored' pretty much.
I wrote a little snippet to round a number to a certain number of significant figures some time ago. You might find it useful
function sigFigs(num, figures) {
var delta = Math.pow(10, Math.ceil(Math.log(num) / Math.log(10)) - figures);
return Math.round(num / delta) * delta;
}
sigFigs(number, 3); // => 8.420e+79

JavaScript addition and subtraction doesn't work but multiplication and division works

var a = 2000000000000000000;
a = a - 1; //Doesn't work
a = a + 1; //Doesn't work
But
a = a * 10; //Works
a = a / 10; //Works
Can anyone explain why this happens?
You can try this example in browser console.
You're running into the limits of JavaScript integer calculus.
The largest integer number, JavaScript can use with full precision is 9007199254740992.
Your number is larger and thus will be internally represented as a double. As a consequence you run into all the problems associated with floating point calculus, which you see here.

Categories