Comparing big numbers in Javascript - javascript

I've got two numbers that I want to compare. The numbers in the following example are the result of 26^26 computed in two different systems. One of which is my javascript code.
However, when comparing the two numbers I end up with something like this:
AssertionError [ERR_ASSERTION]: 4.0329146112660565e+26 == 4.0329146112661e+26
They're obviously not equal, but theoretically they should.
What's the proper way to perform equality on big numbers in javascript (even if it's an approximation)?

If what you're trying to do is determine if two numbers are practically equivalent you'll have to come up with your margin of error. One way to do this is to compute the difference between the numbers and then determine if that difference is significant or not.
So, taking your numbers from before, we could evaluate the difference between these numbers through subtraction. Since we don't really care about the sign of this difference, I'll go ahead and get the absolute value of the difference.
Math.abs(4.0329146112660565e+26 - 4.0329146112661e+26) === 4329327034368
(Sidenote: Now is not the time to explain why, but the == operator in JavaScript has confusing and error-prone behavior, use === when you want to compare values.)
That difference is a HUGE number, but related to how big our numbers are in the first place, it's rather insignificant. Intuitively, I'm tempted to divide the difference by the smallest of our original numbers like so:
4329327034368 / 4.0329146112660565e+26 === 1.0734983136696987e-14
That looks like a pretty small number. Repeat that same operation with a bunch of values and you should be able to determine what you want your margin of error to be. Then, all you'll have to do is perform the same operations with arbitrary numbers and see if that "difference ratio" is small enough for you.
function similar(a, b) {
let diff = Math.abs(a - b);
let smallest = Math.min(Math.abs(a), Math.abs(b));
let ratio = diff / smallest;
return ratio < MARGIN_OF_ERROR;
}
Now I just came up with that way of determining the importance of the difference between two numbers. It might not be a very smart way to compute it, it might be appropriate to some situations and not to others. But the general idea is that you'll have to make a function that determines if two values are close enough with your own definition of "close".
Be aware though, JavaScript is one of the worst languages you can be doing math in. Integers become imprecise when they go beyond Number.MAX_SAFE_INT (which seems to be 9007199254740991 according to Chrome, not sure if it varies between browsers or if that's a standardized constant).

Update: If your target engine is es2020 or above, you can use the new BigInt javascript primitive, for numbers higher than Number.MAX_SAFE_INTEGER
BigInt(4.0329146112660565e+26) === BigInt(4.0329146112661e+26)
//false
See more information in MDN

var a = 4.0329146112660565e+26;
var b = 4.0329146112661e+26;
a = Math.round(a/10e+20)*10e+20
b = Math.round(b/10e+20)*10e+20
a == b;

I would suggest to use one of big numbers library:
big.js (https://www.npmjs.com/package/big.js)
Example:
var x = new Big('4.0329146112660565e+26');
var y = new Big('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.eq(y));
big-numbers (https://www.npmjs.com/package/big-numbers)
Example:
var x = bn.of('4.0329146112660565e+26');
var y = bn.of('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.equals(y));

Related

Simple way to return values approximating a sin/cosin curve, without using trigonometry?

Apologies in advance for a difficult-to-explain question, for which the answer might simply be "no"...
I have a value -1 >= n <= 1
I'd like to increase its amplitude, say by 2: 2*n
I'd also like to adjust its phase, say by .5: 2*n + .5
How can I do this so that when n increases past 1, it flips signs and reduces itself, for example: when n increases to 1.1, the result is actually .9.
I know this can be done using trig, but I'm having difficulty increasing its amplitude and shifting its phase - by the time I'm done doing both I get this expression:
Math.sin(n*1.57 + Math.PI/4)
And to that expression I still need to perform additional calcs/rounding to get my final values; the expression becomes complicated bloated.
I'm wondering if there's a simpler way to get the desired range/values, avoiding trig altogether? I imagine an operator similar to the modulo, except instead of "resetting" to 0, it reduces in value...
Turns out, a triangle wave solves my problem. It gives oscillating values similar to sine (without ease), and it avoids Math.trig and simplifies my formula. I expanded on the formula given in this SO answer as well as these wikipedia formulas.
Fried Brice's answer suggesting sawtooth was on the right track - but triangle wave is better suited for me, and the 1-line formula makes my eyes feel better.
You can explicitly write out the formula in cases for one period, and use recursion for values outside the fundamental period.
E.g.
function notTrig(x) {
switch (true) {
case (x >= 0 && x < 1):
return x
case (x >= 1 && x < 2):
return 2 - x
default:
notTrig(x - 2)
}
}
This should give you a sawtooth signal with mean 1/2, amplitude 1/2, and period 2. You need to handle negatives as well: exercise left to asker ;-)
Edit: It occurs to me after the fact that I'm misusing the term "sawtooth wave" above. The function I am describing is continuous, and the terms I should be using is "triangle wave." That said, I am very pleased with #calipoop's answer.

Check if two objects are equal when they have floating point values?

Writing some test cases for my Javascript program that deals with binary and right now I'm just using stringify to check if the value and expected values are equal:
JSON.stringify(val) === JSON.stringify(expected)
This works fine except for when I have floating point values. This is what happens:
Given Value: [10,20,30,32.400001525878906,{"test":3,"asdf":23}]
Expected Value: [10,20,30,32.4,{"test":3,"asdf":23}]
Test Failed!
So I guess I can't use stringify anymore to check if my two objects/arrays are equal. What's a good way to check if two potentially deeply nested objects/arrays are equal while also taking in to account floating point values? That is, two floating point values should be considered equal if they are 99.99% the same or whatever.
You'll need to test each element in the array in order, and you'll need to do it recursively for objects. This is typically known as a deep comparison or deep equality. You should be able to do this using a recursive function that checks the type(s) of the comparands.
When comparing floating point values, you'll want to use a tolerance. You do this by taking the absolute value of subtracting the two numbers from each other, and then comparing that to either a fixed tolerance value of your choosing, or a small number known as an epsilon.
In JavaScript, the machine epsilon is available as Number.EPSILON, and is defined to be the difference between 1 and the smallest number that is greater than 1 and can be represented as a Number. Similar constants are available in most languages and are typically used for tolerance-based comparisons.
Tolerance-based comparison turns floating point comparisons from simple equality into a subtract and compare. If you'd normally write
if (a === b) { ... }
you'd write that using the absolute value and a tolerance to eliminate floating point weirdness:
var tolerance = Number.EPSILON;
if (Math.abs(a - b) < tolerance) { ... }
If the difference between a and b is smaller than tolerance, you treat them as equal.
For a more nuanced (but possibly overkill for your case) approach, see The Floating Point Guide's section on comparison. The implementation presented there is in Java, but is likely portable to JavaScript without much effort.

How to get some math errors in JavaScript

I'm doing some math in Node.js, and I've run into some situations in which a calculation that I would expect to give an error, such as division by 0 and the logarithm of 0, does not do so.
I've read the documentation and some other Q/As, and I understand that returning things like Infinity and -Infinity is normal behavior in Javascript. I'm not arguing for/against this.
I'm wondering, however, if there's a clever way to make JavaScript give me an error instead of continuing the calculations when this happens. The biggest issue is sometimes, an Infinity or -Infinity will get generated in the middle of a long and complex calculation, and that number will continue to be used, and eventually the overall calculation will simply return a normal number which is simply wrong. It's difficult to debug because we have no way of knowing right off the bat where the error happened, since no error is getting thrown and Infinity is an acceptable number in JS.
While the answer to Best way to prevent/handle divide by 0 in javascript provides an answer for specific, known cases where this might occur, I am seeking a catch-all solution for detecting when this might occur, rather than hunt down every case where it might occur or discover each case as I go.
The short answer is don't use javascript for any serious math. Javascript is fault-tolerant (which is why it has Infinity, -Infinity, -0, and NaN), but math isn't. Math is supposed to fail when you try impossible things.
As Gothdo has stated, creating custom functions for the behavior would work.
If you're doing math on more complicated objects (such as Points, or Vectors, or Spaces) that can be represented by a JSON object, there's a way to overload the vanilla operators.
http://www.2ality.com/2011/12/fake-operator-overloading.html
full source at
https://github.com/rauschma/op_overload
It's slightly tricky, and it's not really any more practical than just using functions, but it's kinda cool.
You can for example make a function divide that throws error if the result if the division is Infinity:
const divide = function(dividend, divisor) {
const result = dividend / divisor
if (Math.abs(result) === Infinity) {
throw new Error("Division by zero")
}
return result
}
Then in calculations, instead of using the division operator, use that function:
const fourDividedByTwo = divide(4, 2) // gives 2
const oneDividedByZero = divide(1, 0) // throws error

Is it possible to convert A string that is an equation with a variable into a equation?

I need to convert a string returned from prompt into an equation, however the parseFloat returns as only the first number, and symbols in an equation, and stops at the variable. The variable will always = x. The program is designed to convert an algebraic expression say 15*x(5^4-56)*17/x=15 into an expression, and calculate the value of x. If someone could show me how to do this, it would help dramatically. I am currently using multiple prompts, having the user put in the equation before x, then the equation after x, then it inserts a variable in between the two, and calculates it's value.
Edit:
I have no variables predefined, and it must work in equations where x > 1000, or x != //an integer.
Thanks in advance!
Seems to be a complex problem...
This is a solution for a simple relaxed version of your problem. Hope you can use some components of this.
Constraints:
answer for x should be integers between 0 and 1000
the left hand side of the expression should be proper javascript syntax
var input = prompt("enter the equation"); //eg: x*x+x+1=241
var parts = input.split('=');
//solving equation starts
var x = 0;
var temp = eval(parts[0]);
while (temp != parts[1] && x<1000){
x++;
temp = eval(parts[0]);
}
var ans = (x<1000)?"answer is "+x:"this program cannot solve this";
//solving equation finishes
alert(ans);
You can replace the "solving equation" part with some numerical methods used in computer science to solve equations (more details here) . You will have to parse the left side of equation and map them to proper javascript expressions (as a string to execute with eval()) if you want to allow users to use your syntax.
Javascript can evaluate strings using the eval function, but the variable as to be defined before hand, and the equation has to be formatted in way that javascript can understand:
var x = 15
var string = "15*x*17/x"
eval(string)
Your example: "15*x(5^4-56)*17/x=15" would not run however, because it would evaluate x(5^4-56) as a javascript expression, which is invalid.
Using all the info, and other mehtods I found about this, I have put together a communinty answer. Anyone is invited to change and/or add their methods to this.
In order to do this with the least work possible for the user and coder, you would implement the following code.
var input = prompt("enter the equation"); //eg: x*x+x+1=241
var parts = input.split('=');
//solving equation starts
var x = 0; //Or the lowest possible value of "x"
var temp = eval(parts[0]);
while (temp != parts[1] && x<1000){ // && x < The highest number to evaluate
x++; //Add the increment (determines the maximum amount of digits) eg x+0.1 for tenths max, x+2 for only even integers etc.
temp = eval(parts[0]);
}
var ans = (x<1000)?"answer is "+x:"this program cannot solve this"; //make sure x< is the same as line 7.
//solving equation finishes
alert(ans);
But, this runs very slowly if you allow tenths, or a range larger than 2000.`
A faster way of running this would be to define arrays allowing any variable (instead of just x) and a different eveulation process such as here. (do the right click view html and click on the first js source to see code) but, this is 2k lines. Both are usable, but the second is more efficient, and can solve multivariate equations.

Same periodic number is different for a if

I'm building a javascript-based web-app;
With a particular data input, a function returns a value of 10/3 = 3.333333333333333 (this is the amound of decimals shown by a colsole.log call); After about 200 lines of code, I have 2 variables (A and B) that contains that value, and I need to check if it is the same value;
The fact is, how is it possible to have an output like this?
console.log(A); //3.333333333333333
console.log(B); //3.333333333333333
console.log(A == B) //false
console.log(A-B == 0) //true??
I can imagine A == B is false due to how numbers are saved in the memory, but I wish it was a true; and what is really unexplainable to me is how comes the last line output is true?
console.log (or even toString) won't show you the full number down to the bit-by-bit difference. The floating point numbers used in JavaScript (and many other languages) are IEEE-754 double-precision floating point, and they're not perfectly precise, small discrepancies appear and can multiply.
Now, if you literally created A and B like this:
var A = 10 / 3;
var B = 10 / 3;
...then both comparisons would be true (proof). So apparently you're getting A one way, and B another, and the fact is that they are ever-so-slightly-different. (I'm quite surprised to hear A == B says false but A - B == 0 says true, though.)
You'll need to round them to the number of digits you think is appropriate, and compare the rounded result.

Categories

Resources