Cardinal Numbers in Standard American English

6

1

Let n be any integer between 1 and 999,999 inclusive. Your challenge is to write a complete program which using stdin or command-line arguments takes in n and outputs the number of times the letter "o" is needed to write all cardinal numbers in standard American English between 1 and n. You can assume that n will always be an integer within the above given range.

You can just use all lowercase letters as I do below. So we count all "o". No need to worry about uppercase "O".

Here is a quick review of how to write English numerals in American English.

one two three four ... nine ten eleven twelve thirteen fourteen ... nineteen twenty 
twenty-one twenty-two ... twenty-nine thirty ... forty ... fifty ... sixty ... 
seventy ... eighty ... ninety ... one hundred ... two hundred ... three hundred ... 
nine hundred ... one thousand ... two thousand ... nine thousand ... ten thousand ... 
eleven thousand ... ninety-nine thousand ... one hundred thousand ... 
two hundred thousand ... nine hundred ninety-nine thousand nine hundred ninety nine.

The hyphen for two digit numbers doesn't matter.

The commas don't matter of course. I excluded them above.

Separation between hundreds and tens doesn't matter because we are only counting the letter "o" so 110 can be written as "one hundred ten", or "one hundred and ten". I excluded the "and" above.

For this challenge "hundred" and "thousand" must be preceded by "one" instead of "a" when being used at the beginning of the number. So 1111 must be "one thousand one hundred eleven" instead of "a thousand one hundred eleven".

Here are some more random numerals to clarify.

219873 = two hundred nineteen thousand eight hundred seventy three
615023 = six hundred fifteen thousand twenty three
617610 = six hundred seventeen thousand six hundred ten
423716 = four hundred twenty-three thousand seven hundred sixteen
386031 = three hundred eighty-six thousand thirty one

Here are some samples for what your code should return.

./mycount 1
1

There's only "one" to write so we need only a single "o".

./mycount 10
3

We only need three o's namely in "one", "two", and "four".

./mycount 101
41

Your code must be self-contained and must not connect to the internet, download any files, perform any query, etc. I can already see somebody using google or mathematica with wolfram alpha to do this.

True code-golf. The shortest code in any language wins. Please post your code with some test cases. In the case of ties, I pick the one with the highest upvotes after waiting at least for two weeks. So everyone feel free to upvote any solutions you like.

Happy coding!

Fixed Point

Posted 2013-12-27T01:51:44.680

Reputation: 557

I think American numbers and numbers in English have the same amount of os - the only difference I know is the ands. – bcsb1001 – 2015-03-14T20:51:21.690

Related: Converting integers to English words

– primo – 2013-12-27T05:02:29.700

4There are so many missing ands I just dropped my biscuit in my cuppa – Bojangles – 2013-12-28T14:41:36.467

Answers

7

R - 54

sum(nchar(gsub("[^o]","",english::english(1:scan()))))

I get 41 for n=101. I hope someone can confirm.

flodel

Posted 2013-12-27T01:51:44.680

Reputation: 2 345

Yes, this works for me, too, although takes 2 seconds for 10000 and 25 seconds for 100000. For 999999, I got 2359000, which took 6 minutes. Nice! – Andreï Kostyrka – 2016-02-28T11:18:01.417

5This will not work if the package english has not been installed. To be fair, you should add the command necessary for installing the package. – Sven Hohenstein – 2013-12-27T10:38:10.950

5I disagree. I have never seen such comment for python answers that contain import X or perl answers with use Y, etc. Having the necessary packages/modules installed is always a given. – flodel – 2013-12-27T12:16:21.003

OK, now I see the point. – Sven Hohenstein – 2013-12-27T13:05:26.710

3

JavaScript 1.8 (150)

function f(n)n<14?(22>>n)&1:n<100?((n/10|0)==4)+f(n%10):n<1e3?f(n/100|0)+f(n%100):f(n/1e3|0)+f(n%1e3)+1;m=readline();for(s=i=0;i++<m;)s+=f(i);print(s)

As written, this will only work in SpiderMonkey js (the one used by Anarchy Golf). If running this in Firefox, replace readline with prompt and print with alert. Use of Mozilla's nonstandard "expression closures" feature means this will not work in any other interpreter unless you insert {return and } in the necessary places (at a cost of 7 characters).

Original test cases:

  • 1 → 1
  • 10 → 3
  • 101 → 41

Some additional ones:

  • 1020 → 726
  • 21667 → 40173
  • 120000 → 262002
  • 999999 → 2359000

PleaseStand

Posted 2013-12-27T01:51:44.680

Reputation: 5 369

3

C - 147 148 157 163 166 172 200

C is the right tool for the job

s;l(x){s+=(22>>x%10&1)+(x/10%10==4)-!((x+89)/2%50);x&&l(x/100%10);}main(x,v)int**v;{for(x=atoi(v[1]);x;x--)l(x),l(x/1000),s+=x>999;printf("%d",s);}

Original tests:

  • 1 -> 1
  • 10 -> 3
  • 101 -> 41

Tests by @PleaseStand :

  • 1020 -> 726
  • 21667 -> 40173
  • 120000 -> 262602
  • 999999 -> 2359000

Plus some of my own random tests: http://qp.mniip.com/p/cy

mniip

Posted 2013-12-27T01:51:44.680

Reputation: 9 396

2

Mathematica 49 58 50 bytes

Without a library or internet access.

StringCount[""<>IntegerName[Range@#,"Words"],"o"]&

Note:

"Words" guarantees that no digits will be left untranscribed into English.

This incorrectly returns one "o". (Emphasis added.)

IntegerName[1020]

1 thousand 20


This yields two "o"'s, as required. (Emphasis added.)

IntegerName[1020,"Words"]

one thousand, twenty


Example

StringCount[""<>IntegerName[Range@#,"Words"],"o"]&[1020]

726

DavidC

Posted 2013-12-27T01:51:44.680

Reputation: 24 524

1

Moo - 137 bytes

s=$string_utils;m=player;i=0;for a in[1..toint(read(m))]i=i+length(s:strip_all_but(s:english_number(a),"o"));suspend(0);endfor m:tell(i);

The suspend(0) is necessary to avoid a Task ran out of ticks for high inputs. Also, this code takes quite a long time to run for very high numbers.

pppery

Posted 2013-12-27T01:51:44.680

Reputation: 3 987

0

Perl - 384

#!/usr/bin/perl
@b=qw(1 1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1);
sub b($){my($b,$m)=shift;if(20>$b){$b[$b];}elsif(100>$b){$m=$b%10;
$b[(($b-$m)/10)+18]+($m?b($m):0);}elsif(1000>$b){$m=$b%100;
b(($b-$m)/100)+($m?b($m):0);}elsif(1000000>$b){$m=$b%1000;
b(($b-$m)/1000)+1+($m?b($m):0);}}
sub c($){my$c=shift;my$d=0;$d+=b($c--)while($c);$d;}
print c($_)."\n"while(<>);

this would run faster with caching but that would increase my score

hildred

Posted 2013-12-27T01:51:44.680

Reputation: 1 329