1

For integers [1, 2, 4, 8, 16, ...] I can use this function:

const validate = num => (num & num - 1) == 0;

Is there an elegant similar way to do it with decimal numbers without using loops?

  • 0.001
  • 0.002
  • 0.004
  • ...
  • 2.048

And it should be possible to use any number of digits after the decimal point based on a initial value.

  • 0.0001 (initial value)
  • 0.0002
  • 0.0004
  • 0.0016
  • ...
  • 1.6384

Now I use the function to determine if there are numbers after decimal comma and count them:

countDecimals(num) {
  if (Math.floor(num.valueOf()) === num.valueOf()) return 0;
  return num.toString().split(".")[1].length || 0;
}

and then I use it:

validateEntryValue(entryValue) {
  const decimalsQuantity = this.countDecimals(entryValue);
  if (decimalsQuantity) {
    const numToMul = Math.pow(10, decimalsQuantity);
    return ((entryValue * numToMul) & (entryValue * numToMul) - 1) == 0;
  }
  return (entryValue & entryValue - 1) == 0;
}

But some result values fail the tests:

  • 0.001 (initial value)
  • 0.002
  • 0.004
  • 0.016
  • 0.02 (should not to be validated because an initial value is not 0.01)
Vadim Khamzin
  • 13
  • 1
  • 3
  • sorry, can you please explain when a number is valid and when not? you want to check whether that decimal value is..? – Alberto Sinigaglia Apr 23 '21 at 15:21
  • You should take into account, that [floating point math can be inaccurate](https://stackoverflow.com/q/588004/8376184). – FZs Apr 23 '21 at 15:49
  • What is your input? Is it just a number or an array? Also there in no mention of initial value in your code. – adiga Apr 23 '21 at 15:57

2 Answers2

1

Note that doing math with floating point numbers can be inaccurate, so verifying them (which requires an exact value) might not work well.

So, you can multiply your number, so that it's an integer, to avoid precision issues and then you can even use your solution on it.

Here's a purely mathematical solution:

const validate = (toVerify, initial) => {
  const num = toVerify / initial //division is like multiplication with the reciprocal!
  return (num & num - 1) == 0
};

console.log(validate(8, 1)) //true
console.log(validate(0.08, 0.01)) //true
console.log(validate(0.008, 0.001)) //true
console.log(validate(0.016, 0.001)) //true
console.log(validate(0.08, 0.001)) //false
FZs
  • 16,581
  • 13
  • 41
  • 50
0

In a Geometric Progression the "nth" term is equal to a * r ** (n-1)

a First Term

n-1 nth term in 0 index

r Common Ratio

You can simply check if the array element obeys the expression mentioned above.

const validateSeq = (seq) => {
  const 
    ratio = (seq[1] || seq[0]) / seq[0],
    res = seq.map((s, i) => seq[0] * ratio ** i === s);
  return res;
};

console.log(JSON.stringify(validateSeq([0.01, 0.02, 0.04, 0.2, 0.16])));
console.log(JSON.stringify(validateSeq([1, 2, 8, 20, 16])));
console.log(JSON.stringify(validateSeq([0.01])));
Som Shekhar Mukherjee
  • 4,701
  • 1
  • 12
  • 28