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

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

Related

xor: N things with variable probabilities

Forgive me; I'm a coder and not a mathematician, so I'm asking this to my own stack. I'm trying to reduce an array of probabilities (0-1), let's say [.1,.3,.5] to find:
The likelihood of all of them happening (simple multiplication, let's call this function AND: probs.reduce((m,p)=>p*m,1)),
1.1 This can be written
any one of them happening (one minus none of them happening 1 - probs.reduce((m,p)=>m*(1-p),1), call it OR), and
2.1 This can be written
XOR ONLY one, no more and no less, of them happening. At first I thought this was simple because if there are only two inputs, the chance of only one happening should be OR minus AND. But as I'm banging my head on this as an array of more than two values, normal XOR logic seems to disintegrate.
3.1 This can be written (verbosely)
Do I need to get the "OR" and then subtractively multiply all possible AND scenarios iteratively? Or is there a non-iterative formula to find out the total probability of exactly one probability in a list longer than two?
0,0,0 should be 0 in my case. 0,.4.0 should yield a .4 of only one happening. 1,.4,0 should yield 0.6. I know that .5,.5 should yield 0.25 chance of only one happening. But I'm really not sure how to calculate the chance of only one .5,.5,.5 without counting on my fingers. My mind is saying I have to loop through each probability, and subtract from it the chance of any others (OR the rest of the array), then OR the final results... but this is speculative. That seems very weird and inefficient. I can't believe this would be an NP-Hard problem, but it's a corner of things I'm not familiar with...
Please answer in visual, logical or programmatic terms, not pure Math if possible...
** Edit here: I don't need to clarify the exact probability of a particular element in the array being exclusive to the others; I'm trying to find the general probability of any of them being exclusive. **
** Edit. This is what I've got now. I'm excluding all other possibilities for each individual one. Is this the fastest way?... *
function And(probs) {
return (probs.reduce((m,p)=>p*m,1));
}
function Or(probs) {
return (1 - probs.reduce((m,p)=>m*(1-p),1));
}
function Xor(probs) {
let _exclusiveProbabilities = [];
for (let k=0; k < probs.length; k++) {
let _others = [];
for (let j = 0; j < probs.length; j++) {
if (j != k) {
_others.push(probs[j]);
console.log(k,'pushed',probs[j]);
}
}
const _anyOtherProb = Or(_others);
_exclusiveProbabilities.push(probs[k] * (1 - _anyOtherProb));
}
return (Or(_exclusiveProbabilities));
}
** edit. Nope, that's great for two but doesn't work for three. **
Let's say you have three probabilities, which we'll call A, B, and C.
The probability of A being the only event that happened is A * (1-B) * (1-C). In other words, in this scenario A happened, but B did not happen and C did not happen.
But, of course it is possible that B was the only successful event, or that C was the successful event. We will need to sum together the probabilities of all of these situations.
So, we are going to need to loop through all of the events, and compute the probability that only that event happened (and all the others failed), and then compute the sum.
For the case of three events, this would be:
( A * (1-B) * (1-C) ) + ( (1-A) * B * (1-C) ) + ( (1-A) * (1-B) * C )
If there are N total events, then there will be a total of N^2 (N squared) total terms in this expression.

Simple floating point maths in 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

Math.log() inaccuracy - How to deal with it? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 7 years ago.
I know that for getting a 10 based logarithm I have to use Math.log() divided by the constant of the natural logarithm of 10.
var e1000 = Math.log(1000) / Math.LN10;
// Result: 2.9999999999999996 instead of
// expected 3.
console.log(e1000);
// Result: 999.999999999999 instead of
// expected 1000.
console.log(Math.pow(10, e1000));
BUT: The result is just an approximation. If I use the calculated value in further calculation the inaccuracy becomes worse.
Am I doing something wrong?
Is there are more elegant way around it then just using Math.ceil()?
The floating point rounding difference is known and coincidentally the 2.9999 is the exact example used in the MDN Math.Log page.
As you mentioned Math.ceiling can be used to alther the result. Likewise you could increase the base number and use a smaller divider to decrease the change of floating errors. e.g.
function log10(value){
return -3 * (Math.log(value * 100) / Math.log(0.001)) - 2;
}
Example: fiddle
As a sidenote, some browsers already support the Math.log10 functionality, you could extend Math to use the function above if it is not implemented with:
if (!Math.log10) Math.log10 = function(value){
return -3 * (Math.log(value * 100) / Math.log(0.001)) - 2;
};
After running that initializer, you can simply use Math.log10() and your code will automatically use the browser functionality where it is (or when it becomes) available. (fiddle)

Generating a random number between a range with a weight/bias?

I am trying to generate a random number between 1 and a maximum. This I don't have a problem doing so and do so with the following:
var max = 200;
var randomNumber = Math.floor(Math.random() * max) + 1;
However in an ideal situation I would like to generate a number between 1 and my maximum however the lower numbers have a higher probability of occurring. I want the variable to be biased towards 1. However my maths skills aren't strong enough to work this out, it would be great if someone could point me in the right direction.
Thank you,
Josh
a simple way will be to just square the result of Math.random(). Since the result of the function is between 0 and 1 , the square will also be in the range [0, 1], but values , for example , 0.5 from it will be mapped to lower ones - 0.25 . You can experiment with powers above 1 until you find an acceptable function.
I got a code in java which does what you want.
You should choose your own probabilities for the int[] prob arrays.
I think it wont be that hard to translate this to js or build smth. equal.
int[] probs;
void initRandom(int n, int[] probabilities)
{
int i,j,begin=0,end=0,sum=0;
int[] probs;
// sum of all propabilitys must be 100%
for(i=0;i<probabilities.length;i++) sum+=probabilities[i];
probs=new int[sum];
// fills numbers from 0 till n-1 in regard to their probabilities
// to the probability array.
for(i=0;i<n;i++)
{
begin=end;
end+=probabilities[i];
for(j=begin;j<end;j++) probs[j]=i;
}
}
int genRandom()
{
return probs[smallRand(probs.length-1)];
}
This is a very general question. First consider this link here
http://en.wikipedia.org/wiki/List_of_probability_distributions#Supported_on_a_bounded_interval
It shows some probability functions which are bounded, which I believe is what you are looking for (since min=1 and max=max).
You can also chose a semi-infine interval, and just ignore all value above your maximum. I think, this could also be acceptable, depending on your application.
Next, chose one of those probabilty functions, that suits you best. For the sake of simplicity, I chose the triangular distribution
The distribution functions are (PDF and CDF)
f(x) = 2/(2*max-1-max^2)*(x-max)
F(x) = 2/(2*max-1-max^2)*(0.5*x^2-max*x-0.5+max)
so I can generate from a uniform distribution on 0-1 a biased distribution by inverting the CDF like
var urand = Math.random();
var a = 2/(2*max-1-max^2);
var randomNumber = max-Math.sqrt(max*max-2*(max-urand/a-0.5));
Cheers
R
The following function i made up gives you a near-one-biased random number
function rand(max) {
var r = Math.random();
r = 1/(101-100 * r);
return Math.floor(r * max) - 1;
}
It only uses simple arithmetics, thus, it should be quite fast.

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.

Categories

Resources