Why is q == 0 in the following script?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
I would think the result should be 10. What is the correct way to subtract these two numbers?
Because numbers in JavaScript are floating-point. They have limited precision.
When JavaScript sees a very long number, it rounds it to the nearest number it can represent as a 64-bit float. In your script, start and end get rounded to the same value.
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
There's no built-in way to do precise arithmetic on large integers, but you can use a BigInteger library such as this one.
As of January 2020, BigInt datatype is going to be added to Javascript. The proposal is currently in Stage 4. It will enable precise calculation for number which are more than 2^53-1 (Number.MAX_SAFE_INTEGER).
BigInt has been shipped in Chrome, Node, Firefox, and is underway in Safari. Read more here.
var start = BigInt('1234567890123456789');
var end = BigInt('1234567890123456799');
var q = end - start;
alert(q)
A BigInt is created by appending n to the end of an integer literal — 10n — or by calling the function BigInt(). It is also different from Number so 1 + 1n will fail.
You can read more about it here from MDN pages
Jason already posted the why. For a solution, you can get a Javascript BigInt library at http://www-cs-students.stanford.edu/~tjw/jsbn/
const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
let s = d - (b[i] || 0)
if (s < 0) {
s += 10
a[i + 1]--
}
return '' + s + r
}, '').replace(/^0+/, ''))
Better use big-integer library for these things so as to handle all different test cases.This is just for the a general case you can use....
It is explained in the JavaScript documentation:
According to the ECMAScript standard, there is only one number type: the double-precision 64-bit binary format IEEE 754 value (numbers between -(253-1) and 253-1). There is no specific type for integers.
Wikipedia page about double precision floating point format explains:
Between 252= 4,503,599,627,370,496 and 253= 9,007,199,254,740,992 the representable numbers are exactly the integers. For the next range, from 253 to 254, everything is multiplied by 2, so the representable numbers are the even ones, etc.
(All integer numbers smaller than 252 are represented exactly.)
1234567890123456789 and 1234567890123456799 are larger than 260= 1152921504606846976. At this magnitude only about 1% of the integer numbers are stored exactly using the double-precision floating point format.
These two cannot be stored exactly. They both are rounded to 1234567890123456800.
The JavaScript documentation also explains how to tell if a an integer number is stored exactly:
[...] and starting with ECMAScript 6, you are also able to check if a number is in the double-precision floating-point number range using Number.isSafeInteger() as well as Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER. Beyond this range, integers in JavaScript are not safe anymore and will be a double-precision floating point approximation of the value.
function add(x, y) {
//*********************************************************************//
// This function adds or subtracts two extremely large decimal numbers //
// Inputs x and y should be numbers, i.e. commas are removed already //
// Use this function to remove commas and convert to number: //
// x = parseFloat(strNumber.replaceAll(",","").trim()); //
// Inputs x and y can be both positive, or both negative, //
// or a combination (i.e. one positive and one negative in any //
// position whether as x or as y) which means subtraction //
//*********************************************************************//
var temp, borrow=false, bothNeg=false, oneNeg=false, neg=false;
if (x < 0 && y < 0) { bothNeg = true; x = -x; y = -y; }
else if (x < 0 || y < 0) {
oneNeg = true;
if (Math.abs(x) == Math.abs(y)) { x = 0; y = 0; }
else if (x < 0 && Math.abs(x) > Math.abs(y)) { neg = true; x = -x; y = -y; }
else if (x < 0 && Math.abs(x) < Math.abs(y)) { temp = y; y = x; x = temp; }
else if (y < 0 && Math.abs(x) < Math.abs(y)) { neg = true; temp = y; y = -x; x = -temp; }
}
x = parseInt(x*1000000000/10).toString();
y = parseInt(y*1000000000/10).toString();
var lenx=x.length, leny=y.length, len=(lenx>leny)?lenx:leny, sum="", div=0, x1, y1, rem;
for (var i = 0; i < len; i++) {
x1 = (i >= lenx) ? 0 : parseInt(x[lenx-i-1]);
y1 = (i >= leny) ? 0 : parseInt(y[leny-i-1]);
y1 = (isNaN(y1)) ? 0 : y1;
if (oneNeg) y1 = -y1;
if (borrow) x1 = x1 - 1;
if (y < 0 && x1 > 0 && Math.abs(x1) >= Math.abs(y1)) { borrow=false; div=0; }
if (y < 0 && y1 <= 0 && (x1 < 0 || Math.abs(x1) < Math.abs(y1))) { borrow=true; rem=(x1+y1+div+10)%10; div=10; }
else { rem=(x1+y1+div)%10; div=Math.floor((x1+y1+div)/10); }
sum = Math.abs(rem).toString() + sum;
}
if (div > 0) sum = div.toString() + sum;
sum = parseFloat(sum*10/1000000000);
if (bothNeg || neg) sum = -sum;
return sum;
}
Related
function doNf(num, left, right) {
let numStr = num.toString();
const numArray = numStr.split('.');
let leftPart = numArray[0]; // Grab the left part of numStr
// Determine how many times to loop based on left and leftPart
const timesToLoop = left - leftPart.length;
if (typeof right === 'undefined') {
for (let i = 0; i < timesToLoop; i++) {
numStr = '0' + numStr; // Add a 0 to the beginning of numStr
}
return numStr;
} else {
let rightRounded = num.toFixed(right); // Round num to right decimals
numStr = rightRounded.toString();
for (let i = 0; i < timesToLoop; i++) {
numStr = '0' + numStr; // Add a 0 to the beginning of numStr
}
}
return numStr;
}
This Function is basically a modified rounding-off function. It works correctly but there are few edge cases that i am unable to handle, need help with that.
for (let i = 0; i < 10; i++) {
const n = Math.pow(10, -i);
console.log(i, n, doNf(n, 4, 2));
}
This gives output like:
0 1 0001.00
1 0.1 0000.10
2 0.01 0000.01
3 0.001 0000.00
4 0.0001 0000.00
5 0.00001 0000.00
6 0.000001 0000.00
7 1e-7 0.00
8 1e-8 0.00
9 1e-9 0.00
case 7,8,9 are behaving incorrectly.
there should be exactly 4 zeros before decimal since left = 4. I even checked that the typeof those 0.00 is string, but i am unable to figure out why the concatanation is not happening??
You should avoid using toString() as that will produce scientific notation. In that case no . is found in the string, which breaks the algorithm.
Instead, use toFixed immediately and pad the result at the left so it has the required digits before the decimal point.
There are maybe some boundary cases to deal with:
When right is 0, there will be no decimal point in the result; the padding should take this into account
When left is 0, you maybe want the results to start with a decimal point. toFixed always produces at least one digit before the decimal point.
When the given number has an absolute value is too great to be represented in the given format, the left restriction is ignored (as padLeft will do).
function doNf(num, left, right) {
let s = num.toFixed(right).padStart(left+right+!!right, "0");
return left ? s : s.replace(/^0/, "");
}
for (let i = 0; i < 10; i++) {
let n = 1 / 10 ** i;
console.log(i, n, doNf(n, 4, 2));
}
I'm having performance issues when trying to check whether integer n is a perfect square (sqrt is a whole number) when using BigInt. Using normal numbers below Number.MAX_SAFE_INTEGER gives reasonable performance, but attempting to use BigInt even with the same number range causes a huge performance hit.
The program solves the Battle of Hastings perfect square riddle put forth by Sam Loyd whereby my program iterates over the set of real numbers n (in this example, up to 7,000,000) to find instances where variable y is a whole number (perfect square). I'm interested in the original square root of one of the 13 perfect squares where this condition is satisfied, which is what my code generates (there's more than one).
Assuming y^2 < Number.MAX_SAFE_INTEGER which is 2^53 – 1, this can be done without BigInt and runs in ~60ms on my machine:
const limit = 7_000_000;
var a = [];
console.time('regular int');
for (let n = 1; n < limit; n++) {
if (Math.sqrt(Math.pow(n, 2) * 13 + 1) % 1 === 0)
a.push(n);
}
console.log(a.join(', '));
console.timeEnd('regular int');
Being able to use BigInt would mean I could test for numbers much higher than the inherent number variable limit 2^53 - 1, but BigInt seems inherently slower; unusably so. To test whether a BigInt is a perfect square, I have to use a third party library as Math.sqrt doesn't exist for BigInt such that I can check if the root is perfect, as all sqrt returns a floor value. I adapted functions for this from a NodeJS library, bigint-isqrt and bigint-is-perfect-square.
Thus, using BigInt with the same limit of 7,000,000 runs 35x slower:
var integerSQRT = function(value) {
if (value < 2n)
return value;
if (value < 16n)
return BigInt(Math.sqrt(Number(value)) | 0);
let x0, x1;
if (value < 4503599627370496n)
x1 = BigInt(Math.sqrt(Number(value))|0) - 3n;
else {
let vlen = value.toString().length;
if (!(vlen & 1))
x1 = 10n ** (BigInt(vlen / 2));
else
x1 = 4n * 10n ** (BigInt((vlen / 2) | 0));
}
do {
x0 = x1;
x1 = ((value / x0) + x0) >> 1n;
} while ((x0 !== x1 && x0 !== (x1 - 1n)));
return x0;
}
function perfectSquare(n) {
// Divide n by 4 while divisible
while ((n & 3n) === 0n && n !== 0n) {
n >>= 2n;
}
// So, for now n is not divisible by 2
// The only possible residual modulo 8 for such n is 1
if ((n & 7n) !== 1n)
return false;
return n === integerSQRT(n) ** 2n;
}
const limit = 7_000_000;
var a = [];
console.time('big int');
for (let n = 1n; n < limit; n++) {
if (perfectSquare(((n ** 2n) * 13n) + 1n))
a.push(n);
}
console.log(a.join(', '));
console.timeEnd('big int');
Ideally I'm interested in doing this with a much higher limit than 7 million, but I'm unsure whether I can optimise the BigInt version any further. Any suggestions?
You may be pleased to learn that some recent improvements on V8 have sped up the BigInt version quite a bit; with a recent V8 build I'm seeing your BigInt version being about 12x slower than the Number version.
A remaining challenge is that implementations of BigInt-sqrt are typically based on Newton iteration and hence need an estimate for a starting value, which should be near the final result, so about half as wide as the input, which is given by log2(X) or bitLength(X). Until this proposal gets anywhere, that can best be done by converting the BigInt to a string and taking that string's length, which is fairly expensive.
To get faster right now, #Ouroborus' idea is great. I was curious how fast it would be, so I implemented it:
(function betterAlgorithm() {
const limit = 7_000_000n;
var a = [];
console.time('better algorithm');
let m = 1n;
let m_squared = 1n;
for (let n = 1n; n < limit; n += 1n) {
let y_squared = n * n * 13n + 1n;
while (y_squared > m_squared) {
m += 1n;
m_squared = m * m;
}
if (y_squared === m_squared) {
a.push(n);
}
}
console.log(a.join(', '));
console.timeEnd('better algorithm');
})();
As a particular short-term detail, this uses += 1n instead of ++, because as of today, V8 hasn't yet gotten around to optimizing ++ for BigInts. This difference should disappear eventually (hopefully soon).
On my machine, this version takes only about 4x as much time as your original Number-based implementation.
For larger numbers, I would expect some gains from replacing the multiplications with additions (based on the observation that the delta between consecutive square numbers grows linearly), but for small-ish upper limits that appears to be a bit slower. If you want to toy around with it, this snippet describes the idea:
let m_squared = 1n; // == 1*1
let m_squared_delta = 3n; // == 2*2 - 1*1
let y_squared = 14n; // == 1*1*13+1
let y_squared_delta = 39n; // == 2*2*13+1 - 1*1*13+1
for (let n = 1; n < limit; n++) {
while (y_squared > m_squared) {
m_squared += m_squared_delta;
m_squared_delta += 2n;
}
if (y_squared === m_squared) {
a.push(n);
}
y_squared += y_squared_delta;
y_squared_delta += 26n;
}
The earliest where this could possibly pay off is when the results exceed 2n**64n; I wouldn't be surprised if it wasn't measurable before 2n**256n or so.
I solved the following leetCode problem with some code :
You have d dice, and each die has f faces numbered 1, 2, ..., f.
Return the number of possible ways modulo 10^9 + 7 to roll the dice so the sum of the face up numbers equals t.
I made two versions of the solution code, one in node.js using mathjs, and one in python using the math module .
In node.js
const { combinations: comb, bignumber: Big } = require("mathjs");
function dice(d, f, t) {
if (t > d * f || t < d) return 0;
var result = Big(0);
var i = 0;
var sign = 1;
var n = t - 1;
var k = t - d;
while (k >= 0 && i <= d) {
result = result.add(
comb(Big(d), Big(i))
.times(comb(Big(n), Big(k)))
.times(sign)
);
i++;
n -= f;
k -= f;
sign *= -1;
}
return result;
}
console.log(
dice(30, 30, 500).mod(
Big(10)
.pow(9)
.add(7)
)
);
In python :
import math
def dice(d, f, t):
if t > d * f or t < d:
return 0
result = 0
i = 0
sign = 1
n = t - 1
k = t - d
while k >= 0 and i <= d:
result += math.comb(d, i) * math.comb(n, k) * sign
i += 1
n -= f
k -= f
sign *= -1
return result
print(dice(30, 30, 500) % (math.pow(10, 9) + 7))
Now when i run the code with these parameters : d=30 f=30 t=500 (the last line of each version of the code), i expect the result to be 222616187 .
In the node.js version , that's exactly what i get .
But in the python version , i'm getting 811448245.0 i can't figure out why is that happening .
So why is there a difference in the results ?
The math module usesfloat, not arbitrary precision int.
math - Mathematical functions
[...]
The following functions are provided by this module. Except when
explicitly noted otherwise, all return values are floats.
Since math.pow returns a float, the leading argument to % is converted to a float as well.
The result of dice(30, 30, 500) is too large to be accurately represented as a float. Its float representation is off by -14999044413600247749080617.
The ** operator and its function version operator.pow do not force float conversion and provide an integer if all parameters are integers.
>>> print(dice(30, 30, 500) % (10 ** 9 + 7))
222616187
Solved, in a weird way. It turns out, math.pow returns a float instead of int and somehow bugged. I think int % float has a different cast operation in it and treated differently by the compiler. It can be investigated further. If you cast it to int, that would be your answer.
import math
def dice(d, f, t):
if t > d * f or t < d:
return 0
result = 0
i = 0
sign = 1
n = t - 1
k = t - d
while k >= 0 and i <= d:
result += math.comb(d, i) * math.comb(n, k) * sign
i += 1
n -= f
k -= f
sign *= -1
return result
print(dice(30, 30, 500) % int((math.pow(10, 9) + 7)))
How can I calculate how many zeros come after the decimal point but before the first non-zero in a floating point number. Examples:
0 -> 0
1 -> 0
1.0 -> 0
1.1 -> 0
1.01 -> 1
1.00003456 ->4
Intuitively I assume there is a math function that provides this, or at least does the main part. But I can neither recall nor figure out which one.
I know it can be done by first converting the number to a string, as long as the number isn't in scientific notation, but I want a pure math solution.
In my case I don't need something that works for negative numbers if that's a complication.
I'd like to know what the general ways to do it are, irrespective of language.
But if there is a pretty standard math function for this, I would also like to know if JavaScript has this function.
As a sidenote, I wonder if this calculation is related to the method for determining how many digits are required for the decimal representation of an integer.
Let x be a non-whole number that can be written as n digits of the whole part, then the decimal point, then m zeroes, then the rest of the fractional part.
x = [a1a2...an] . [0102...0m][b1b2...bm]
This means that the fractional part of x is larger than or equal to 10–m, and smaller than 10–m+1.
In other words, the decimal logarithm of the fractional part of x is larger than or equal to –m, and smaller than –m+1.
Which, in turn, means that the whole part of the decimal logarithm of the fractional part of x equals –m.
function numZeroesAfterPoint(x) {
if (x % 1 == 0) {
return 0;
} else {
return -1 - Math.floor(Math.log10(x % 1));
}
}
console.log(numZeroesAfterPoint(0));
console.log(numZeroesAfterPoint(1));
console.log(numZeroesAfterPoint(1.0));
console.log(numZeroesAfterPoint(1.1));
console.log(numZeroesAfterPoint(1.01));
console.log(numZeroesAfterPoint(1.00003456));
As a sidenote, I wonder if this calculation is related to the method for determining how many digits are required for the decimal representation of an integer.
In the same manner, a positive integer x takes n decimal digits to represent it if and only if n - 1 <= log10(x) < n.
So the number of digits in the decimal representation of x is floor(log10(x)) + 1.
That said, I wouldn't recommend using this method of determining the number of digits in practice. log10 is not guaranteed to give the exact value of the logarithm (not even as exact as IEEE 754 permits), which may lead to incorrect results in some edge cases.
You can do it with a simple while loop:
function CountZeros(Num) {
var Dec = Num % 1;
var Counter = -1;
while ((Dec < 1) && (Dec > 0)) {
Dec = Dec * 10;
Counter++;
}
Counter = Math.max(0, Counter); // In case there were no numbers at all after the decimal point.
console.log("There is: " + Counter + " zeros");
}
Then just pass the number you want to check into the function:
CountZeros(1.0034);
My approach is using a while() loop that compares the .floor(n) value with the n.toFixed(x) value of it while incrementing x until the two are not equal:
console.log(getZeros(0)); //0
console.log(getZeros(1)); //0
console.log(getZeros(1.0)); //0
console.log(getZeros(1.1)); //0
console.log(getZeros(1.01)); //1
console.log(getZeros(1.00003456)); //4
function getZeros(num) {
var x = 0;
if(num % 1 === 0) return x;
while(Math.floor(num)==num.toFixed(x)) {x++;}
return(x-1);
}
You can do it with toFixed() method, but there is only one flaw in my code, you need to specify the length of the numbers that comes after the point . It is because of the way the method is used.
NOTE:
The max length for toFixed() method is 20, so don't enter more than 20 numbers after . as said in the docs
var num = 12.0003400;
var lengthAfterThePoint = 7;
var l = num.toFixed(lengthAfterThePoint);
var pointFound = false;
var totalZeros = 0;
for(var i = 0; i < l.length; i++){
if(pointFound == false){
if(l[i] == '.'){
pointFound = true;
}
}else{
if(l[i] != 0){
break;
}else{
totalZeros++;
}
}
}
console.log(totalZeros);
Extra Answer
This is my extra answer, in this function, the program counts all the zeros until the last non-zero. So it ignores all the zeros at the end.
var num = 12.034000005608000;
var lengthAfterThePoint = 15;
var l = num.toFixed(lengthAfterThePoint);
var pointFound = false;
var theArr = [];
for(var i = 0; i < l.length; i++){
if(pointFound == false){
if(l[i] == '.'){
pointFound = true;
}
}else{
theArr.push(l[i]);
}
}
var firstNumFound = false;
var totalZeros = 0;
for(var j = 0; j < theArr.length; j++){
if(firstNumFound == false){
if(theArr[j] != 0){
firstNumFound = true;
totalZeros = totalZeros + j;
}
}else{
if(theArr[j] == 0){
totalZeros++;
}
}
}
var totalZerosLeft = 0;
for (var k = theArr.length; k > 0; k--) {
if(theArr[k -1] == 0){
totalZerosLeft++;
}else{
break;
}
}
console.log(totalZeros - totalZerosLeft);
What is the fastest way to count the number of significant digits of a number?
I have the following function, which works, but is quite slow due to string operations.
/**
* Count the number of significant digits of a number.
*
* For example:
* 2.34 returns 3
* 0.0034 returns 2
* 120.5e+3 returns 4
*
* #param {Number} value
* #return {Number} The number of significant digits
*/
function digits (value) {
return value
.toExponential()
.replace(/e[\+\-0-9]*$/, '') // remove exponential notation
.replace( /^0\.?0*|\./, '') // remove decimal point and leading zeros
.length
};
Is there a faster way?
Update: here a list of assertions to test correct functioning:
assert.equal(digits(0), 0);
assert.equal(digits(2), 1);
assert.equal(digits(1234), 4);
assert.equal(digits(2.34), 3);
assert.equal(digits(3000), 1);
assert.equal(digits(0.0034), 2);
assert.equal(digits(120.5e50), 4);
assert.equal(digits(1120.5e+50), 5);
assert.equal(digits(120.52e-50), 5);
assert.equal(digits(Math.PI), 16);
My own method failed for digits(0), I fixed that by adding a ? to the second regexp.
Here's a more mathematical way of doing the same operation (which appears to be significantly faster)
JSPerf comparing the three implementations
Accurate for integer n < +-(2^53) per http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
Floats are converted to a string and then coerced to an int (by removing the decimal so similar rules apply)
var log10 = Math.log(10);
function getSignificantDigitCount(n) {
n = Math.abs(String(n).replace(".", "")); //remove decimal and make positive
if (n == 0) return 0;
while (n != 0 && n % 10 == 0) n /= 10; //kill the 0s at the end of n
return Math.floor(Math.log(n) / log10) + 1; //get number of digits
}
Slight improvement of regular expression
function digits (value) {
return value
.toExponential()
.replace(/^([0-9]+)\.?([0-9]+)?e[\+\-0-9]*$/g, "$1$2")
.length
};
And yet another approach, that uses string operations and handles some special cases for better performance:
function digits(value) {
if (value === 0) {
return 0;
}
//create absolute value and
var t1 = ("" + Math.abs(value));
//remove decimal point
var t2 = t1.replace(".","");
//if number is represented by scientific notation,
//the places before "e" (minus "-" and ".") are the
//significant digits. So here we can just return the index
//"-234.3e+50" -> "2343e+50" -> indexOf("e") === 4
var i = t2.indexOf("e");
if (i > -1) {
return i;
}
//if the original number had a decimal point,
//trailing zeros are already removed, since irrelevant
//0.001230000.toString() -> "0.00123" -> "000123"
if (t2.length < t1.length) {
// -> remove only leading zeros
return t2.replace(/^0+/,'').length;
}
//if number did not contain decimal point,
//leading zeros are already removed
//000123000.toString() -> "123000"
// -> remove only trailing zeros
return t2.replace(/0+$/,'').length;
}
You can directly examine the bytes of a floating-point value by using typed arrays. The advantages of doing this are that it's fast, and it doesn't require any math to be done. You can look directly at the bits of the mantissa.
You can start with this:
var n = yourFloatingPointValue;
var f64 = new Float64Array(1);
var dv = new DataView(f64.buffer);
dv.setFloat64(0, n, false); // false -> big-endian
var bytes = [];
for (var i = 0; i < 8; i++)
bytes.push(dv.getUint8(i));
Now the bytes array contains integers representing the 8-bit values of the floating point value as it looks in memory. The first byte contains the sign bit in the top bit position, and the first 7 bits of the exponent in the rest. The second byte contains the 5 least-significant bits of the exponent and the first three bits of the mantissa. The rest of the bytes are all mantissa.
Regular string checking. A slight of improvement though.
function digits(value) {
value = "" + value;
var res = 0;
for (var i = 0, len = value.length; i < len; i++){
if (value[i]==="e")break;
if (+value[i]>=0)
res++;
}
return res;
};
jsperf Benchmark testing result as compared to the OP's and other answers code.
Update
function digits(value) {
console.log(value);
value = "" + (+value);
var res = 0;
for (var i = 0, len = value.length; i < len; i++) {
if (value[i] === "e")
{
break;
}
if (+value[i] >= 0)
{
res++;
}
}
console.log(value);
return res;
}
function check(val1, val2) {
console.log( val1+"==="+val2 +" = "+ (val1 === val2));
return val1 === val2;
}
check(digits(0), 1);
check(digits(2), 1);
check(digits(1234), 4);
check(digits("0012003400"), 8);
check(digits("0022.002200"), 6);
check(digits(2.34), 3);
check(digits(3000), 4);
check(digits(0.0034), 2);
check(digits(12003), 5);
check(digits(1.23e+50), 3);
check(digits("1.23e+50"), 3);
check(digits(120.5e51), 4);
check(digits(1120.5e+52), 5);
check(digits(120.52e-53), 5);
check(digits(Math.PI), 16);
There is a faster and indirect way to do it, which is converting it to a string and finding the length of it.
a = 2.303
sig_fig = len(str(a))-len(str(int(a)))-1
The extra -1 is for the "."