Determine number of leading zeros in a floating point number - javascript

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);

Related

javascript function edge cases solving

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));
}

how to write javascript code to get three significant digit after decimal

I have a requirement to format a no to get 3 significant digit after a decimal in javascript..
detail about the significant digit can be found here http://www.usca.edu/chemistry/genchem/sigfig.htm
here are the rule for significant digit
1) ALL non-zero numbers (1,2,3,4,5,6,7,8,9) are ALWAYS significant.
2) ALL zeroes between non-zero numbers are ALWAYS significant.
3) ALL zeroes which are SIMULTANEOUSLY to the right of the decimal point AND at
the end of the number are ALWAYS significant.
4) ALL zeroes which are to the left of a written decimal point and are in a number >= 10 are ALWAYS significant.
i want function like
function significantDigit(no, noOfDecimal)
{
return signifcantNo
}
Example of significant digits.
48,923 has five significant digit..significantDigit(no,3) should return 48923
3.967 has four significant digit..significantDigit(no,3) should return 3.967
0.00104009 has six significant digit,..significantDigit(no,3) should return .00104
hope this helps
var anumber=123.45
anumber.toPrecision(6) //returns 123.450 (padding)
anumber.toPrecision(4) //returns 123.5 (round up)
anumber.toPrecision(2) //returns 1.2e+2 (you figure it out!)
thanks for the edited question
this one ll solve your requirement
var anumber = 123.4050877
var str = anumber.toPrecision(6)
var a = [];
a= JSON.parse("[" + str + "]");
alert(a.length)
for(var i=6;i<=a.length;i--){
if(a[i]=="0"){
a.splice(i, 1);
}
}
alert(a)
i have found a java code here thanks to Pyrolistical
Rounding to an arbitrary number of significant digits
public static double roundToSignificantFigures(double num, int n) {
if(num == 0) {
return 0;
}
final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
final int power = n - (int) d;
final double magnitude = Math.pow(10, power);
final long shifted = Math.round(num*magnitude);
return shifted/magnitude;}
i have converted this to a javascript code, this can be found at http://jsfiddle.net/f6hdvLjb/4/
javascript code is
function roundToSignificantFigures(num, n) {
if(num === 0) {
return 0;
}
var d = Math.ceil(Math.log10(num < 0 ? -num: num));
var power = n - parseInt(d);
var magnitude = Math.pow(10, power);
var shifted = Math.round(num*magnitude);
alert(shifted/magnitude);
return shifted/magnitude;
}
roundToSignificantFigures(6666666.0412222919999,3);
i think this is what the significant digit logic.
this may not be the complete solution..but its correct to the most extent (i think) it works really great for very big decimal no..this will give you most significant digit after decimal
function signiDigit(val, noOfdecimalPoint) {
debugger;
var noString = String(val);
var splitNo = noString.split(".");
if (splitNo.length > 1) {
if(parseInt(splitNo[0])!==0 ||splitNo[0]==='' )
{
if(noString.length - 1 > noOfdecimalPoint)
{
return Math.round(val);
}else
{
return val;
}
}else
{
var noafterDecimal =String(parseInt(splitNo[1]));
if(noafterDecimal.length > noOfdecimalPoint)
{
return parseFloat(val.toFixed(splitNo[1].indexOf(noafterDecimal) + noafterDecimal.length-1));
}
else{
return val;
}
}
}}
var no = signiDigit(9.999,3);
alert(no);
here is the fiddeler link http://jsfiddle.net/n1gt4k90/4/
this is not the complete significant no but mix of significant and rounding.

how to divide a number a in a series of all whole numbers?

Hi sorry for asking this if this is a stupid question.
I would like to ask how to securely divide a number in Javascript that it will always
output the result in a way that it will output pure whole numbers.
example:
10 / 2 ---> 5, 5 ( it would be 2 fives so it is whole number )
BUT
10 / 3 ---> 3, 3, 4 ( it would have two 3 and one 4 so that it would still result to 10 )
10/3 will give you 3.333333..., never four... if you want to check is a number will give you "whole numbers" as you say, use modulo (%).
Modulo finds the remainder of division of one number by another.
For example
10%5 = 0 because 10 divided by 5 is a "whole number"
10%3 = 1 because the closest 10/3 is 3... 3x3=9... 10-9=1
So in your code, if you want to know if a number divided by another number is whole, you need to do
if (number1%number2 == 0) { ... }
Read more about it here
EDIT :
I read your question again and I think this fiddle is what you want
var number1 = 10,
number2 = 3;
if (number1 / number2 == 0) {
alert('the numbers are whole');
} else {
var remainder = number1%number2;
var wholes = Math.floor(number1 / number2);
var output = '';
for (var i = 0; i < (wholes - 1); i++) {
output+= number2 + ', ';
}
output += (number2 + remainder);
alert(output);
}
Whatever your result is,just pass it through the parseInt function,For Eg:-
Suppose your answer is 4.3,
The whole number close to it will can be accounted using,
parseInt(4.3)
Which equals 4.
Another posibility: make the number a string and walk all the elements
var a = 11 / 4;
//turn it into a string and remove all non-numeric chars
a = a.toString().replace(/\D/g, '');
//split the string in seperate characters
a = a.split("");
var num = new Array();
//convert back to numbers
for (var i = 0; i < a.length; i++) {
num.push(parseFloat(a[i]));
}
alert(num);
On a sidenote, you'll have to do some kind of rounding, to prevent eternally repeating numbers, like 10/3.
Here is a fiddle
Look at this very simple example:
var x = 10;
var y = 3;
var result = x/y;
var rest = x%y;
for (var i=0; i<y; i++) {
var output;
if(i==y-1){
output = parseInt(result + rest);
}
else{
output = parseInt(result);
}
alert(output);
}
http://jsfiddle.net/guinatal/469Vv/4/

What is the fastest way to count the number of significant digits of a number?

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 "."

Subtracting long numbers in javascript

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;
}

Categories