2

Somebody wrote this (very terrible) function to translate a numeric value from 0-999 to English words.

function getNumberWords(number) {
  var list = new Array(1000);
  list[000] = "zero";
  list[001] = "one";
  list[002] = "two";
  list[003] = "three";
  ///skip a few
  list[099] = "ninety nine";
  list[100] = "one hundred";
  list[101] = "one hundred and one";
  ///skip a few more
  list[997] = "nine hundred and ninety seven";
  list[998] = "nine hundred and ninety eight";
  list[999] = "nine hundred and ninety nine";
  return list[number];
}

There is some rather odd bug in here that I can't seem to figure out the cause of. Some, but not all of the elements are placed in the wrong cell.

I tried displaying the contentes of the list and it showed a pretty funky result:

> list.toString();
"zero,one,two,three,four,five,six,seven,ten,eleven,twelve,thirteen,fourteen,
fifteen,sixteen,seventeen,twenty,twenty one,twenty two,twenty three,twenty four,
twenty five,twenty six,twenty seven,thirty,thirty one,thirty two,thirty three,
thirty four,thirty five,thirty six,thirty seven,forty,forty one,forty two,"
///(skip a few)
"sixty six,sixty seven,seventy,seventy one,seventy two,seventy three,seventy four,
seventy five,seventy six,seventy seven,,,,,sixty eight,sixty nine,,,,,,,,,
seventy eight,seventy nine,eighty,eighty one,eighty two,eighty three,eighty four,"
///(and so on)

That is, elements 0-7 have the expected value. Elements 68, 69, and 78-999 also have the expected values. Elements 64-67 and 70-77 are empty. Elements 8-63 have incorrect values.

What in the world is going on here? Why are 15 cells empty, 56 cells incorrect, and the rest correct?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Peter Olson
  • 139,199
  • 49
  • 202
  • 242

5 Answers5

5

Numeric literals starting with 0 are interpreted as octal values (if they can be) — that is, numbers in base-8. This is the case in Javascript, C, C++, PHP, Perl, Bash and many other languages.

Now, base-8 22 is base-10 18 so you're not accessing the elements that you think you are. Your first eight array elements were fine because, naturally, base-8 0 is also base-10 0, and so on up to 7. A value like 069 did not cause confusion because it cannot represent anything in base-8, so Javascript falls back to base-10. Yuck!


I suggest using spacing for alignment instead:

function getNumberWords(number) {
  var list = new Array(1000);
  list[  0] = "zero";
  list[  1] = "one";
  list[  2] = "two";
  list[  3] = "three";
  ///skip a few
  list[ 99] = "ninety nine";
  list[100] = "one hundred";
  list[101] = "one hundred and one";
  ///skip a few more
  list[997] = "nine hundred and ninety seven";
  list[998] = "nine hundred and ninety eight";
  list[999] = "nine hundred and ninety nine";
  return list[number];
}

I also suggest making a new function that generates the strings on-the-fly; it shouldn't be taxing and certainly no more so than creating this array on every call.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
4

In Javascript 022 means 22 in octal (18 in decimal).

Octal numeral system on Wikipedia

kapa
  • 77,694
  • 21
  • 158
  • 175
  • To complete the thought -- 22 in octal is 2*8 + 2 = 18 in decimal, which is the 19th element of the array (since the first element is at index 0). – Ted Hopp Nov 09 '11 at 17:35
  • @Ted Thanks, added the result to my answer. – kapa Nov 09 '11 at 17:41
3

Starting a number literal with a 0 in non-strict code may cause that number to be parsed as an Octal literal (base 8). For instance, 010 is parsed to a number with the value 8.

Octal literals are now deprecated and will not be parsed as octals in strict mode, using "use strict":

function a() {
    alert(010);
    // -> 8
} 
function b() {
    "use strict";
    alert(010);
    // -> 10
} 

Not all browser support strict mode, so for now just change your code to make sure numbers do not start with a 0, or wrap them in strings:

list[  21 ] = "something"
list["022"] = "something else";

Strings work because octal numbers are not coerced.

Community
  • 1
  • 1
Andy E
  • 338,112
  • 86
  • 474
  • 445
2

The 0-prefix means octal in JavaScript, so 022 is octal:

022 = 2*8^1+2*8^0 = 18

And since the first index i 0, 18 gives the 19th element.

Kleist
  • 7,785
  • 1
  • 26
  • 30
1

In JavaScript, numbers beginning with 0 are interpreted as octal (base 8).

For example, 010 === 8.

Oddly, JavaScript will interpret the number as decimal (base 10) even if it has an octal prefix, if the number is impossible to reach in octal.

For example, 08 === 8.

Paul Rosania
  • 9,823
  • 2
  • 20
  • 18
  • 2
    That is one of the reasons octal literals were deprecated. Not only are they confusing, this quirk makes them doubly so. They should have thrown an error from the start. – Andy E Nov 09 '11 at 17:41