Simple floating point maths in JavaScript - javascript

I need to do some basic floating point math stuff (adding and multiplying money) for a website UI. I know that Javascript floats aren't accurate because of how they're stored, but I also know that somehow, it's possible to get the level of accuracy I require. I know this because Google's calculator can do it (type "calculator" into the Goog)..
Anyway, I don't want to have to send my little numbers back to the server and have to wait for a response, so I'm trying to use a library called BigNumbers.js, but I can't figure out how to make it spit out numbers (or strings) no matter what I call, it returns a BigNumber object.
Here's my test code: JSFiddle
floats = [145, 1.44, 1.3];
sum = new BigNumber(0);
for(i=0; i<floats.length; i++){
sum = sum.times(floats[i]);
}
// sum = sum.toDigits(); //returns object
// sum = sum.toString(); //returns 0
console.log(sum); // expecting 271.44, getting object
How can I achieve the expected result? If there's a better library to use, that would be an acceptable answer as well.
Thank you.

You'll want to initialize sum to 1 instead of 0 (and maybe change its name to product), and then call .toString() when you pass it to console.log():
console.log(sum.toString());
edit — also, as pointed out in a comment, you should set the number of decimal places (to 2, probably) and also set the rounding mode. You can do that via the BigNumber.config() call.

You can go just fine with the JavaScript floating values and Math.round(..) method used to round cents:
var floats = [145, 1.44, 1.3];
sum = 1;
for (i=0; i<floats.length; i++){
sum = Math.round(sum * floats[i] * 100)/100;
}
console.log(sum.toFixed(2)); // expecting 271.44

Related

How to properly deal with Javascript float representation errors? [duplicate]

This question already has answers here:
How to deal with floating point number precision in JavaScript?
(47 answers)
Closed 1 year ago.
For example:
sum = 0.00;
sum += 46.85 * 0.1;
console.log(sum) // 4.6850000000000005
sum += 179.29 * 0.1;
console.log(sum) // 22.613999999999997
I believe I've had this happen with simple additions and simple multiplications as well.
I understand this is a consequence of the inability to hold floats properly in a computer, which is fine. However, Postgres, as far as I can tell, seems to handle these operations fine with the same numbers. Seems strange that Javascript doesn't seem to, unless I'm missing something.
Anyway, my current fix is to run it like this:
const fixFloatError = (n) => {
decimalDigitLength = n.match(/\.(\d+)/)[1].length;
return parseFloat(parseFloat(n).toFixed(decimalDigitLength - 1));
}
let n = String(46.85 * 0.1);
n = fixFloatError(n);
If you're wondering why I'm converting it to a string beforehand, it's because Javascript will automatically turn a float like 22.6139999999999997 into 22.614 as it enters the function (Which is correctly fixed! Regardless of whether you hardcoded that number into the variable or generated it by multiplication), and things like 4.6850000000000005 into 4.6850000000000005 (which hasn't changed). So to get a consistent function that works for both cases I'm passing in the float as a string to maintain its form.
Surely I'm missing something here and there's a simpler solution?
Just multiply the float by some factor of 10 to create a larger integer portion. Then round the remainder and divide back down by that same factor.
let sum = 46.85 * 0.1;
console.log(sum) // 4.6850000000000005
sum = (Math.round(sum * 1000000000)) / 1000000000;
console.log(sum); // 4.685

Comparing big numbers in 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));

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.

Better random function in JavaScript

I'm currently making a Conway's Game of Life reproduction in JavaScript and I've noticed that the function Math.random() is always returning a certain pattern. Here's a sample of a randomized result in a 100x100 grid:
Does anyone knows how to get better randomized numbers?
ApplyRandom: function() {
var $this = Evolution;
var total = $this.Settings.grid_x * $this.Settings.grid_y;
var range = parseInt(total * ($this.Settings.randomPercentage / 100));
for(var i = 0; i < total; i++) {
$this.Infos.grid[i] = false;
}
for(var i = 0; i < range; i++) {
var random = Math.floor((Math.random() * total) + 1);
$this.Infos.grid[random] = true;
}
$this.PrintGrid();
},
[UPDATE]
I've created a jsFiddle here: http://jsfiddle.net/5Xrs7/1/
[UPDATE]
It seems that Math.random() was OK after all (thanks raina77ow). Sorry folks! :(. If you are interested by the result, here's an updated version of the game: http://jsfiddle.net/sAKFQ/
(But I think there's some bugs left...)
This line in your code...
var position = (y * 10) + x;
... is what's causing this 'non-randomness'. It really should be...
var position = (y * $this.Settings.grid_x) + x;
I suppose 10 was the original size of this grid, that's why it's here. But that's clearly wrong: you should choose your position based on the current size of the grid.
As a sidenote, no offence, but I still consider the algorithm given in #JayC answer to be superior to yours. And it's quite easy to implement, just change two loops in ApplyRandom function to a single one:
var bias = $this.Settings.randomPercentage / 100;
for (var i = 0; i < total; i++) {
$this.Infos.grid[i] = Math.random() < bias;
}
With this change, you will no longer suffer from the side effect of reusing the same numbers in var random = Math.floor((Math.random() * total) + 1); line, which lowered the actual cell fillrate in your original code.
Math.random is a pseudo random method, that's why you're getting those results. A by pass i often use is to catch the mouse cursor position in order to add some salt to the Math.random results :
Math.random=(function(rand) {
var salt=0;
document.addEventListener('mousemove',function(event) {
salt=event.pageX*event.pageY;
});
return function() { return (rand()+(1/(1+salt)))%1; };
})(Math.random);
It's not completly random, but a bit more ;)
A better solution is probably not to randomly pick points and paint them black, but to go through each and every point, decide what the odds are that it should be filled, and then fill accordingly. (That is, if you want it on average %20 percent chance of it being filled, generate your random number r and fill when r < 0.2 I've seen a Life simulator in WebGL and that's kinda what it does to initialize...IIRC.
Edit: Here's another reason to consider alternate methods of painting. While randomly selecting pixels might end up in less work and less invocation of your random number generator, which might be a good thing, depending upon what you want. As it is, you seem to have selected a way that, at most some percentage of your pixels will be filled. IF you had kept track of the pixels being filled, and chose to fill another pixel if one was already filled, essentially all your doing is shuffling an exact percentage of black pixels among your white pixels. Do it my way, and the percentage of pixels selected will follow a binomial distribution. Sometimes the percentage filled will be a little more, sometimes a little less. The set of all shufflings is a strict subset of the possibilities generated this kind of picking (which, also strictly speaking, contains all possibilities for painting the board, just with astronomically low odds of getting most of them). Simply put, randomly choosing for every pixel would allow more variance.
Then again, I could modify the shuffle algorithm to pick a percentage of pixels based upon numbers generated from a binomial probability distribution function with a defined expected/mean value instead of the expected/mean value itself, and I honestly don't know that it'd be any different--at least theoretically--than running the odds for every pixel with the expected/mean value itself. There's a lot that could be done.
console.log(window.crypto.getRandomValues(new Uint8Array(32))); //return 32 random bytes
This return a random bytes with crypto-strength: https://developer.mozilla.org/en/docs/Web/API/Crypto/getRandomValues
You can try
JavaScript Crypto Library (BSD license). It is supposed to have a good random number generator. See here an example of usage.
Stanford JavaScript Crypto Library (BSD or GPL license). See documentation for random numbers.
For a discussion of strength of Math.random(), see this question.
The implementation of Math.random probably is based on a linear congruential generator, one weakness of which is that a random number depends on the earlier value, producing predictable patterns like this, depending on the choice of the constants in the algorithm. A famous example of the effect of poor choice of constants can be seen in RANDU.
The Mersenne Twister random number generator does not have this weakness. You can find an implementation of MT in JavaScript for example here: https://gist.github.com/banksean/300494
Update: Seeing your code, you have a problem in the code that renders the grid. This line:
var position = (y * 10) + x;
Should be:
var position = (y * grid_x) + x;
With this fix there is no discernible pattern.
You can using the part of sha256 hash from timestamp including nanoseconds:
console.log(window.performance.now()); //return nanoseconds inside
This can be encoded as string,
then you can get hash, using this: http://geraintluff.github.io/sha256/
salt = parseInt(sha256(previous_salt_string).substring(0, 12), 16);
//48 bits number < 2^53-1
then, using function from #nfroidure,
write gen_salt function before, use sha256 hash there,
and write gen_salt call to eventListener.
You can use sha256(previous_salt) + mouse coordinate, as string to get randomized hash.

Neural Network Continuous tanh-Sigmoid Activation Function and Random Weights

I really need help implementing a continuous tanh-sigmoid activation function in a very basic neural network. If you could give a basic example that would be great, but if you could change it in my source code I would be extremely grateful! Also, what range should the random weights be initiated with (i.e. what range)?
The weight range depends on what input data range you have. In some implementations the weights can also be negative.
For possible Sigmoid functions, check here (tanh is not the only possibility):
http://en.wikipedia.org/wiki/Sigmoid_function
Tip: You can typically compute the NN with matrix multiplications.
http://www.dtreg.com/mlfn.htm
http://en.wikipedia.org/wiki/Neural_network
P.S.: probably not a good idea to do this in JavaScript.
you can either implement it via exp(x) , See: http://www.javascripter.net/faq/mathfunc.htm
sinh(x) exp(x) - exp(-x) exp(2x) - 1
tanh(x) = ------- = ------------------ = -------------
cosh(x) exp(x) + exp(-x) exp(2x) + 1
that gives you:
function tanh(x) {
e = Math.exp(2*x);
return (e - 1) / (e + 1) ;
};
another solution is to store a table with the tanh function values in an array, and define a JavaScript function which interpolates the tanh values for x based on the tanh values stored in the array
typically people don't want [-inf...+inf] as the range of the input values, and don't want [-1...+1] as the range of output values -- therefore you might need a different sigmoid function!
you need to take the expected range of input values, and the expected range of output values, and use those to shift the actual sigmoid function, the weight-ranges and the value of the threshhold.
a threshhold of 0.7 or larger is typically used. You need to experiment with that.
this.output = 2 / (1 + Math.exp(-2 * input)) - 1;

Categories

Resources