I'm working on a html5 sound fader widget using the Soundmanager2 library, and I have a function that should be setting a variable to interpolate between 0-100 across 15 seconds, but it takes more than 15 seconds the first time and then less each time after. That inconsistency is driving me nuts.
my js is here: http://wesww.com/nic/peasoup9/js/soundfader.js
CODE:
I'm setting a 15 second duration:
function fadeOutSound(soundObject) {
var fadeLengthInSeconds = 15;
And am doing some math here:
if(soundObject.volume < maximumVolume) {
var progressRatio = deltaTime / soundObject.fadeLength;
var actualProgress = progressRatio * maximumVolume;
soundObject.setVolume( soundObject.volume + actualProgress );
Thanks for any help / tips you might have! If I can add any info/code to make clearer, please let me know
Edit: I ended up going with a self-adjusting timer, such as this: http://www.sitepoint.com/creating-accurate-timers-in-javascript/
All numbers in JavaScript are, by definition, 64-bit floats. The various JavaScript-engines, however, usually type-cast them into simpler number formats if possible (I'm pretty sure at least V8 does this.)
While I haven't played with it myself, it seem Typed Arrays are currently the best trick to make maths perform on a larger scale. It only works on "modern" browsers, though.
You may want to take a look at the division.
I am suspecting there is a error like this:
10/3 = 3
where all numbers are casted to integer.
Related
I'm using this BigInteger.js for some calculations:
let myBigInt = bigInt(20).pow(200) // gets 160693804425899027554196209234116260252220299378279283530137600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I'd like to apply the logarithm to the big integer but in the docs I could not find any matching function. How can I implement a log(baseN, valueX) function for the BigInteger.js library?
Note: let myLogarithm = myBigInt.log(baseN) is not a valid implementation.
Note: After a lot of try&error I did found a working solution my own and I will post it here because I'm pretty sure there are a few more people then me that also gots faced with the same issue right there. So I hope, I could help :)
Have a look at wikipedia, as I did because theres a very nice article about baseConversion.
Below you can find a function for Math.log(base, value) that is able to calculate the log(base) from a value.
Math.log = (function() {
var log = Math.log;
return function(base, n) {
return log(n)/(base ? log(base) : 1);
};
})();
To calculate the logarithmToBaseN for bigInt-values just use this line of code:
let logarithmToBaseN = (myBigInt.toString().length * Math.log(baseN, 10) + Math.log(baseN, parseFloat("0." + myBigInt))) - 1);
Edit: This soltuion is a tiny workaround bacause parseFloat("0." + myBigInt) converts a big value like 100000 to a really small one like 0.100000,... what causes that it will be in integer precision.
According to #Jonas W's comment: The solution is very accurate for lower bases like (5, 10, ...) combined with low values like 10, 1000, 100000 - but for really big values like bigInt(20).pow(200) is it not.
Note: Using parseFloat (IEEE 754 double precision floating-point) means, you have a maximum of 52 bits of precision, which is a bit more than 15 decimal places. After that - the accuracy will be killed.
Note: For really big values bigInt(20).pow(200) combined with really big Bases like 100*(and more) it seems to be pretty accurate again.
Greetings, jonas.
I'm dealing with relatively small and simple numbers. I first tried to do the rounding (2 signs after digit) with infamous toFixed. It's a known issue: sometimes it works incorrectly. But what struck me is the fact that it also works inconsistently:
(0.395).toFixed(2); // "0.40"
(0.295).toFixed(2); // "0.29"
These numbers are very similar, 3 signs after digit and yet different behavior.
So, I decided to switch to using Math.round. Shortly, I encountered another problem:
Math.round(0.35055 * 10000) / 100; // produces 35.05 instead of 35.06
Is Math.round also problematic? Then, what method should be used?
Unfortunately JavaScript is known to have such precision issues, issues that are better explained in the following question: Is floating point math broken?, as pointed in the comments.
If you require a greater degree of numerical accuracy, I would suggest you to use a library such as BigNumber, which also comes with its own toFixed method.
Your example would look something like this:
var a = new BigNumber('0.35055');
a = a.times(10000)
a = a.dividedBy(100)
console.log(a.toFixed(2)); //would log "35.06"
For brevity you can also chain the operations, like this: a.times(10000).dividedBy(100).toFixed(2)
I think this is working as designed. Keep in mind these numbers are stored in base 2, so there is a loss of precision when converting to and from base 10. And you have to look at these conversions if you want to understand why it looks inconsistent. If you have a fixed number of decimals that you want to keep precisely, you can use integers for operations and convert only for display.
I've tried big.js, bignumber.js, and decimal.js; they all work reasonably well up to a certain point, but fall short when I need to do arbitrary-precision calculations with large enough numbers of "odd" digits (my current test case is 31435517643980 * (1 / 31435517643980) === 1). I am open to any solution that allows me to process expressions like this, including calls to an external API. I'm currently looking at Wolfram|Alpha's API, but the 2000 calls/month limit is a restriction I'd like to avoid, because my application is going to be making quite a few calls.
If this is the wrong SE site for this question, please let me know and/or move it.
Possibly the most common way to do this is simply multiply both numbers by the same multiplier to make them have no decimals, and then do the operation, then divide again. Here's a crude implementation:
function getDigits(n){
return n.toString().substring(n.toString().indexOf('.')+1).length;
}
function xNums(n1,n2){
var highRes=(n1*Math.pow(10,getDigits(n1))*(n2*Math.pow(10,getDigits(n2))));
return highRes/Math.pow(10,getDigits(n1))/Math.pow(10,getDigits(n2));
}
Then, run xNums(31435517643980,(1 / 31435517643980))===1. Works for me in Chrome
How do I generate cryptographically secure random numbers in javascript?
There's been discussion at WHATWG on adding this to the window.crypto object. You can read the discussion and check out the proposed API and webkit bug (22049).
Just tested the following code in Chrome to get a random byte:
(function(){
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
alert(buf[0]);
})();
In order, I think your best bets are:
window.crypto.getRandomValues or window.msCrypto.getRandomValues
The sjcl library's randomWords function (http://crypto.stanford.edu/sjcl/)
The isaac library's random number generator (which is seeded by Math.random, so not really cryptographically secure) (https://github.com/rubycon/isaac.js)
window.crypto.getRandomValues has been implemented in Chrome for a while now, and relatively recently in Firefox as well. Unfortunately, Internet Explorer 10 and before do not implement the function. IE 11 has window.msCrypto, which accomplishes the same thing. sjcl has a great random number generator seeded from mouse movements, but there's always a chance that either the mouse won't have moved sufficiently to seed the generator, or that the user is on a mobile device where there is no mouse movement whatsoever. Thus, I recommend having a fallback case where you can still get a non-secure random number if there is no choice. Here's how I've handled this:
function GetRandomWords (wordCount) {
var randomWords;
// First we're going to try to use a built-in CSPRNG
if (window.crypto && window.crypto.getRandomValues) {
randomWords = new Int32Array(wordCount);
window.crypto.getRandomValues(randomWords);
}
// Because of course IE calls it msCrypto instead of being standard
else if (window.msCrypto && window.msCrypto.getRandomValues) {
randomWords = new Int32Array(wordCount);
window.msCrypto.getRandomValues(randomWords);
}
// So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
// sjcl might help us out here
else if (sjcl.random.isReady()) {
randomWords = sjcl.random.randomWords(wordCount);
}
// Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
// so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
// have to make to crack the password.
else {
randomWords = [];
for (var i = 0; i < wordCount; i++) {
randomWords.push(isaac.rand());
}
}
return randomWords;
};
You'll need to include sjcl.js and isaac.js for that implementation, and be sure to start the sjcl entropy collector as soon as your page is loaded:
sjcl.random.startCollectors();
sjcl is dual-licensed BSD and GPL, while isaac.js is MIT, so it's perfectly safe to use either of those in any project. As mentioned in another answer, clipperz is another option, however for whatever bizarre reason, it is licensed under the AGPL. I have yet to see anyone who seems to understand what implications that has for a JavaScript library, but I'd universally avoid it.
One way to improve the code I've posted might be to store the state of the isaac random number generator in localStorage, so it isn't reseeded every time the page is loaded. Isaac will generate a random sequence, but for cryptography purposes, the seed is all-important. Seeding with Math.random is bad, but at least a little less bad if it isn't necessarily on every page load.
You can for instance use mouse movement as seed for random numbers, read out time and mouse position whenever the onmousemove event happens, feed that data to a whitening function and you will have some first class random at hand. Though do make sure that user has moved the mouse sufficiently before you use the data.
Edit: I have myself played a bit with the concept by making a password generator, I wouldn't guarantee that my whitening function is flawless, but being constantly reseeded I'm pretty sure that it's plenty for the job: ebusiness.hopto.org/generator.htm
Edit2: It now sort of works with smartphones, but only by disabling touch functionality while the entropy is gathered. Android won't work properly any other way.
Use window.crypto.getRandomValues, like this:
var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);
This is supported in all modern browsers and uses the operating system's random generator (e.g. /dev/urandom). If you need IE11 compatibility, you have to use their prefixed implementation viavar crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) though.
Note that the window.crypto API can also generate keys outright, which may be the better option.
Crypto-strong
to get cryptographic strong number from range [0, 1) (similar to Math.random()) use crypto:
let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;
console.log( random() );
You might want to try
http://sourceforge.net/projects/clipperzlib/
It has an implementation of Fortuna which is a cryptographically secure random number generator. (Take a look at src/js/Clipperz/Crypto/PRNG.js). It appears to use the mouse as a source of randomness as well.
First of all, you need a source of entropy. For example, movement of the mouse, password, or any other. But all of these sources are very far from random, and guarantee you 20 bits of entropy, rarely more. The next step that you need to take is to use the mechanism like "Password-Based KDF" it will make computationally difficult to distinguish data from random.
Many years ago, you had to implement your own random number generator and seed it with entropy collected by mouse movement and timing information. This was the Phlogiston Era of JavaScript cryptography. These days we have window.crypto to work with.
If you need a random integer, random-number-csprng is a great choice. It securely generates a series of random bytes and then converts it into an unbiased random integer.
const randomInt = require("random-number-csprng");
(async function() {
let random = randomInt(10, 30);
console.log(`Your random number: ${random}`);
})();
If you need a random floating point number, you'll need to do a little more work. Generally, though, secure randomness is an integer problem, not a floating point problem.
I know i'm late to the party, but if you don't want to deal with the math of getting a cryptographically secure random value, i recommend using rando.js. it's a super small 2kb library that'll give you a decimal, pick something from an array, or whatever else you want- all cryptographically secure.
It's on npm too.
Here's a sample I copied from the GitHub, but it does more than this if you want to go there and read about it more.
console.log(rando()); //a floating-point number between 0 and 1 (could be exactly 0, but never exactly 1)
console.log(rando(5)); //an integer between 0 and 5 (could be 0 or 5)
console.log(rando(5, 10)); //a random integer between 5 and 10 (could be 5 or 10)
console.log(rando(5, "float")); //a floating-point number between 0 and 5 (could be exactly 0, but never exactly 5)
console.log(rando(5, 10, "float")); //a floating-point number between 5 and 10 (could be exactly 5, but never exactly 10)
console.log(rando(true, false)); //either true or false
console.log(rando(["a", "b"])); //{index:..., value:...} object representing a value of the provided array OR false if array is empty
console.log(rando({a: 1, b: 2})); //{key:..., value:...} object representing a property of the provided object OR false if object has no properties
console.log(rando("Gee willikers!")); //a character from the provided string OR false if the string is empty. Reoccurring characters will naturally form a more likely return value
console.log(rando(null)); //ANY invalid arguments return false
<script src="https://randojs.com/2.0.0.js"></script>
If you need large amounts, here's what I would do:
// Max value of random number length
const randLen = 16384
var randomId = randLen
var randomArray = new Uint32Array(randLen)
function random32() {
if (randomId === randLen) {
randomId = 0
return crypto.getRandomValues(randomArray)[randomId++] * 2.3283064365386963e-10
}
return randomArray[randomId++] * 2.3283064365386963e-10
}
function random64() {
if (randomId === randLen || randomId === randLen - 1) {
randomId = 0
crypto.getRandomValues(randomArray)
}
return randomArray[randomId++] * 2.3283064365386963e-10 + randomArray[randomId++] * 5.421010862427522e-20
}
console.log(random32())
console.log(random64())
I'm tried to make some world generation mechanism using Math.random() whenever I needed something random, but then decided that I wanted it seed-based, so, given a seed, I changed all of the Math.random() to Math.sin(seed++)/2+0.5, hoping it would do the same thing, but would be the same if the seed was the same seed.
Then someone made me notice that the sin wave hasn't got even distribution, and finally I saw why some of my code was working strangely.
I was wondering if there was a simple fix, or if there isn't, another very simple seed based randomizer like this
So, I looked at your method, t1wc, and I found that it isn't actually evenly distributed. It is significantly more likely to spit out numbers near 0 or near 1 than it is to spit out numbers near 0.5, for example. This is just a consequence of the way that the sine function works.
Instead, you might try using a method called Blum Blum Shub (named after the authors of the original paper, wonderfully). It is evenly distributed and quite fast. Given a seed, it works as follows:
Square the seed and put the result in a temporary variable (x).
Take the mod of x base M.
M is a product of two large primes.
The value of x is a new seed to be used for future calculations.
Return x/M as your pseudo-random number. It will be evenly distributed between 0 and 1.
Below is a simple implementation of a Blum Blum Shub:
var SeededRand = function(seed, mod1, mod2)
{
return function()
{
seed = (seed*seed) % (mod1*mod2);
return seed/(mod1*mod2);
};
};
If you want to make a new random number generator, you just call:
var rand = SeededRand(seed, mod1, mod2);
Where seed is some initial seed (1234567890 works well), and mod1 and mod2 are some large primes (7247 and 7823 work well). rand is just a variable that I've defined to hold the output.
Now, to start getting random values, you just call:
rand();
Which will spit out a different value each time you run it.
If you have any questions, please ask!
There is a very nice seed-based randomizing script already made. It can be found here.
ok guys, found out this is what I'm really looking for:
(((Math.sin(seed.value++)/2+0.5)*10000)%100)/100
It sends out even spreaded numbers, and I guess it's a lot simpler than any other number generator I've seen