-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
64 bit precision #4
Comments
That is true. However that code only scales the 64 bit number to a [0,1) double and a double can't hold a 64 bit integer anyway. The end result is that some bits are truncated, thus the randomness is maintained. That being said, I think there is a risk that the output range is [0, 1] because of this truncation. To solve this I think one should do as sugested in: http://xorshift.di.unimi.it/ x = UINT64_C(0x3FF) << 52 | x >> 12;
double d = *((double *)&x) - 1.0; |
51d7ce3 fixes the issue. Unfortunately it is about 5 times slower than before. /cc @emilbayes any ideas |
A faster solution might be to construct the IEEE double indirectly using The solution that I attempted looks like this: // :: t2 = randomint()
var t2 = this.randomint();
var t2U = t2[0];
var t2L = t2[1];
// :: s = t2 >> 12
var a1 = 12;
var m1 = 0xFFFFFFFF >>> (32 - a1);
var xU = t2U >>> a1;
var xL = (t2L >>> a1) | ((t2U & m1) << (32 - a1));
var x = xU * Math.pow(2, 32) + xL;
return x * Math.pow(2, -52); and has almost no performance penalty. However there are some cases where this is not exactly equal to the explicit casting method that uses a This is quite tricky to debug because values may have multiply representations in IEEE: For example I see that depending on the casting method
|
@AndreasMadsen I implement transformation without |
@fanatid Wow, that is amazing. I will try to see if I can understand it. The IEEE 754 multiplication algorithms are still quite mysterious for me. |
@AndreasMadsen there is a simple formula: |
That part I do understand, but it doesn't explain how one can manipulate the bits by multiplication and addition. Sometimes multiplication will change the matissa, other times it will change the exponent. For example multiplication with 2 could bitshift the matissa by one or substract one from the exponent. Both are correct, but bitshifting could have consequences for the existing precision while substracing could have consequences for the future precision. |
I inserted your code into my test/debug setup. It works as you say. But interestingly enough it does produces different binary representations.
I understand that the two representations are the same, but in my implementation they sometimes where exactly the same. Because it added the exponent when it should have multiplied the matissa or vice versa. I looks good, but I will have to test this for a ginormous dataset to be sure. |
I think we shouldn't think about ieee754 at all. 9007199254740991 is max integer represented in js -- 53 bits, knowing this we can write |
I never could get @fanatid's solution to match the reference. The current implementation uses a slow buffer approach. |
How about this:
I hard-coded the numbers for performance. Also:
They are not the same. "buffer" is actually 1.0000114440936734. In IEEE 754, every value has a unique binary representation, except NaN. |
Excellent, that appears to work. If you want street creds you can submit a PR. But without the hard-coded optimization, V8 optimizes it for you :)
Yeah, I realized that later, as I became wiser with the years. |
When it comes to browsers, at least one doesn't (IE11). :)
Sure, why not: #11 |
18446744073709551616 is not a number you can represent in JS. It looks as if the logic of the code assumes that you can represent full 64bit number.
The text was updated successfully, but these errors were encountered: