Using the javascript function
function squareIt(number) {
return number * number;
}
When given the number 4294967296 the function returns 18446744073709552000 is returned
Everyone knows the real answer is 18446744073709551616 :-)
I guess this is to to with rounding on my 32-bit machine. However, would this script give the right answer on a 64 bit machine? Has anyone tried this?
ChrisV- see this post. Also it easier for people to evaluate your question by typing the following JavaScript directly into the browser URL textbox:
javascript:4294967296*4294967296
what about this
function squareIt(number){
return Math.pow(number,2)
}
Javascript uses 64 bit floating point arithmetic internally for numerical calculations - the results you see are a reflection of this, and will happene regardless of the underlying architecture.
Here is one more example based on BigInteger.js.
alert(bigInt(4294967296).square());
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.40/BigInteger.min.js"></script>
Related
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.
Let me be brief. I'm trying to calculate
alert((Math.pow(7,35))%71)
but it gives me 61, when the result must be 70. What's wrong?
As others mentioned before with regards to using Math.pow(7,35), this resulting number is way too big for Javascript to handle.
To resolve your problem you need to use an external javascript library.
(Or write your own ;) )
Here are some examples of Javascript libraries that handle big numbers.
BigNum
Bignumber
I hope it helps.
The number you're using is too big for javascript. The max size of an int is 2^53 -- which is less than 7^35.
The only value which requires more precision is an intermediate result. So the problem can also be avoided without the need for higher precision variables when you have an algorithm that doesn't need the problematic intermediate result.
The following formula can be useful for that:
(a.b) % c = (a % c)(b % c) % c
This means Math.pow(7,35)%71 = ((Math.pow(7,17)%71) * (Math.pow(7,18)%71)) % 71.
Now the intermediate results are smaller, but might still be too big. So we need to split up further and to apply the modula operator on smaller intermediate results.
So you can do something like this:
Math.pow((Math.pow(7,7)%71),5)%71
But you probably need to do this for integer numbers wich are variable (otherwise, you could have avoided the problem by hardcoding the result).
So, you need to have an idea about the range of values you can expect and to define an algoritm that splits up the power calculation into pieces that will always have results that are small enough when the input is within the expected range.
And whatever you choose for a calculation like this, calculation with higher precision variables (using a specialized library) or a specilized algoritm, you should always assert the input to make sure your calculation returns a value only when you are sure it can deliver a correct value. Otherwise your implementation becomes unreliable for anyone who isn't aware of the range in which it is valid. Otherwise return an exception with a message that tells clearly which input or combination of inputs is the problem and why.
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
I was using this function for a long time and was happy with it. You probably saw it millions of times. It is even in the example section of the MDN documentation for Math.random()!
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
};
However when I called it on really large range it performed really poorly. Here are some results:
for(var i=0;i<100;i++) { console.log(random(0, 34359738368)) }
34064924616
6800671568
30945277424
2591785504
16404206304
29609031808
14821448928
10712020504
26471102024
21454653384
33180253592
28189739360
27189739528
1159593656
24058421888
13727549496
21995862272
20907450968
28767901872
8055552544
2856286816
28137132160
22775692392
21141911808
16418994064
28151646560
19928528408
11100796192
24022825648
17873139800
10310184976
7425284936
27043756016
2521657024
2864339728
8080550424
8812058632
8867252312
18571554760
19600873680
33687248280
14707542936
28864740112
26338252144
7877957776
28207487968
2268429496
14461565136
28062983608
5637084472
29651319832
31910601904
19776200528
16996597392
2478335752
4751145704
24803500872
21899551216
23144535632
19854787112
8490486080
14932659320
8625736560
11379900040
32357265704
33852039680
2826278800
4648275784
27363699728
14164020752
22279817656
25238815424
16569505656
30065335928
9904863008
26944796040
23179908064
19887944032
27944730648
16242926184
6518696400
25727832240
7496221976
19014687568
5685988776
34324757344
12538943128
21639530152
9532790800
25800487608
34329978920
10871183016
23748271688
23826614456
11774681408
667541072
1316689640
4539806456
2323113432
7782744448
Hardly random at all. All numbers are even.
My question is this: What is the CANONICAL way (if any) to overcome this problem? I have the impression that the above random function is the go-to function for random numbers in range. Thanks in advance.
The WebCrypto API (supported in draft by all the major browsers) provides cryptographically random numbers....
/* assuming that window.crypto.getRandomValues is available */
var array = new Uint32Array(10);
window.crypto.getRandomValues(array);
console.log("Your lucky numbers:");
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
W3C standard
https://www.w3.org/TR/WebCryptoAPI/
Example from here.
https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues
The answer in general is don't use Math.random. It gets the job done, but it's not especially good. On top of that, any number in Javascript greater than 0xffffffffUL isn't represented by integer values--it's an IEEE 754 value with a behavior noted on the MDN site: "Note that as numbers in JavaScript are IEEE 754 floating point numbers with round-to-nearest-even behavior...."
And that's what you're seeing.
If you want larger random numbers, then you'll probably have to get something like Mersenne Twister or Blum-Blum-Shub 32-bit random integer values and multiply them. That will eliminate the rounding-off problem.
Thats wierd! Well you know there is no such thing as truly random when in comes to computers. There is always an algorithm used. So you found a number that causes even's for this particular algorithm.
I tried it out, it isn't necessarily caused by large numbers. More likely some kind of factorization of the number instead. Just try another number, even larger if you like and you should get output that isn't all even. Ex. 134359738368 which is even larger doesn't out all odd or even numbers.
This problem is being asked with a node.js server in mind, but I stated the question as "javascript" because I will likely use this same logic for a client-side script, as well.
Here's the problem: given a set of x values, y needs to scale in a logarithmic way. The Math object performs a natural log [ln(x)], but does not provide an interface for specifying the base of the logarithm.
For a specific example, I need to find the following:
log[512](2)
Which should return .1111~
However, I do not see an interface that allows me to accomplish this, nor can I seem to find a library that exposes an option for the log's base. Surely this is a common problem and has a solution, but my searching has only found solutions for different/unrelated problems. Ideas?
You can use the logarithm base change formula:
log[a](n) = log[b](n) / log[b](a)
So in order to get log(2) base 512, use:
function log(b, n) {
return Math.log(n) / Math.log(b);
}
alert(log(2, 512));
Note that Math.log above uses the natural log base; i.e., it would be written as ln mathematically.
I found this answer as a first result in google today, and if anyone else finds it too, there's a small mistake. The correct version is as follows:
function log(b, n) {
return Math.log(n) / Math.log(b);
}