2

I'm trying to get the length of a float in JavaScript, but I I can't make it work as a string:

var length = ((x + '').toString().length;

because, undefined is a very regular and possible value of the variable, so I end up getting the length of "undefined"...

I see various possible solutions:

  • Allocate every float's digit in a array with number.isFloat() and count arrays's length.

  • By finding an mathematical solution alike: (Math.log10((newValue ^ (newValue >> 31)) - (newValue >> 31)) | 0) + 1, but applied to float values and not only integers.

  • Some dummy function that loops every digit.

  • Use a specific math library (http://mathjs.org/), which seems to me like the best solution, since I am not being able to find any working function that will perform this task without damaging the performance.

Danziger
  • 19,628
  • 4
  • 53
  • 83
Vladimir
  • 456
  • 1
  • 7
  • 20
  • 1
    what exactly is the "length" of a float to you? what do you need that for? – Thomas May 31 '17 at 22:42
  • @Thomas "9.75" - length of 4 or 3 without dot. – Vladimir May 31 '17 at 22:43
  • 1
    Like this? (With dot only) https://jsfiddle.net/lixusrarnavo/5oy379eg/ – Lixus May 31 '17 at 22:46
  • 1
    then how about `const len = v => isNaN(v)? 0: String(+v).length` or `const len = v => isNaN(v)? 0: String(+v).length - (+v === Math.floor(v));` if you don't want to count the dot, or `const len = v => String(v).match(/\d/g).length` wich simply counts the digits in the passed value. – Thomas May 31 '17 at 22:48
  • exactly, but sadly, I can't use a string to count it's length. I wonder there won't be any kind of short function that I could apply – Vladimir May 31 '17 at 22:48
  • 2
    Why can't you use String to count the length? If you mean values like `undefined`, well the snippet takes care of these. It returns 0 for everything that is **N**ot **a N**umber. – Thomas May 31 '17 at 22:49
  • Because, when the user uses an invalid value, (`max`, `min`, `step`) on a `number` type `input`, it's value is automatically `undefined`. Then I am applying an conditional: `float == undefined && [length-of-the-float] >= max`,these conditionals enter in conflict with each other. I solved this silly issue with not reading the newest value, which is imposing to be undefined, but last value, so I actually could apply it as string over the last value – Vladimir May 31 '17 at 23:01
  • So the problem wasn't in "Lenght of a float" but rather a logical problem, I forgot that the value is undefined, and by testing it again to answer you better, got what were happening. Thank you all – Vladimir May 31 '17 at 23:03
  • 1
    @Thomas Note the first option will not work for `null` because `isNaN(null)` returns `false` and `String(+null)` returns `'0'`, so it's `.length` will be 1 instead of 0. The second one will work though. – Danziger May 31 '17 at 23:05
  • @Claies Thanks, everything is possible though – Vladimir Jun 01 '17 at 06:26
  • 1
    In order to answer a question you have to understand the question; I have merely attempted to try and explain why I (and maybe others) find the question confusing. You can clarify the question or not, that's up to you. – Claies Jun 01 '17 at 11:32
  • 1
    @VladimirLisovets Did anyone solve your problem? If so, could you please accept the best answer (click the checkmark under the points). That will help other users that come across your question quickly spot the accepted answer and it also gives 15 rep. points to the author (: – Danziger Jan 31 '18 at 05:25
  • 1
    @Danziger Thank you very much, I did mark your question. – Vladimir Feb 09 '21 at 15:26

2 Answers2

2

What about checking first if number is actually numeric and then, if it is, returning the length of its string representation:

let numbers = [undefined, null, 12345, 1.2345, '12345', '1.2345', 'abcd', '1.2345abcd', 0.1 + 0.2, 0.3, {}, []]

console.log(numbers.map(number => {
  return number === null || isNaN(number) ? 0 : number.toString().length;
}));

The above snippet considers strings that actually represent a number: 12345, 1.2345... as numbers.

It will return 0 for undefined, objects, arrays and null, but note we need to explicitly check for null as it may not be intuitive, but isNaN(null) will return false. See this other answer for a detailed explanation on that.

If you don't want to count the ., you have multiple options:

  • Replace '.' with '' from the string representation of the number using String.prototype.replace().
  • Once you know the number is actually a number, check if it is a float doing number % 1 !== 0 and, if it is, then subtract 1 from its .length.

You mention that you think mathjs might be the best option to avoid harming performance, but a custom implementation to do exactly what you need is probably faster than a full blown-up library to handle "math" in general.

Also, you should probably take a look at this: https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil.

Anyway, there are a few other special cases you should consider in your custom implementation if you go for that that the library might already be handling properly, obviously with some extra work. Have you noticed what the length of 0.1 + 0.2 was according to my code? 19! How come? It looks quite obvious that 0.1 + 0.2 is 0.3, so its length should be 3. Actually, the next item on the list is 0.3 and it works fine for that one.

Well, it turns out floating-point numbers have some precision issues. I'm not going to get into that now, but you can read about it here: https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems.

And here you can see an example:

console.log(0.1, 0.2, 0.3, 0.1 + 0.2)
Danziger
  • 19,628
  • 4
  • 53
  • 83
1

To find the length of a float number without experiencing issues with undefined, use try, catch, and throw.

var num = document.getElementById("num").value;
  var result = document.getElementById("result").value;
var parsedFloat;

function foo() {
  num = document.getElementById("num").value;
  result = document.getElementById("result").value;

  try {
    if (num == parseFloat(num) && num !== undefined) { // if number is equal to that number turned into a float; "1.2" becomes 1.2 and "thiswontwork" becomes NaN (not a number)
      parsedFloat = num;
      if (parsedFloat != parseInt(parsedFloat)) { // if it's a float, not an integer
        parsedFloat = parsedFloat.substring(1); // removes the last digit so that the length will be subtracted because of decimal point
      } // currently, I do not have anything for ".0".
      result = parsedFloat.length;
    } else {
      throw "Must be a number!";
    }
  } catch(err) {
    result = err;
  } finally {
    document.getElementById("result").value = result;
  }
}
<input id="num" placeholder="insert number here"><br>
<input id="result" placeholder="result">
<br>
<button onclick="foo()">Click me!</button>
Christian
  • 132
  • 1
  • 14