This commit is contained in:
Ingy döt Net 2013-06-05 21:47:54 +00:00
parent 1f1ad49427
commit 6f050a029e
2496 changed files with 37609 additions and 3031 deletions

View file

@ -1,60 +1,78 @@
import std.stdio, std.string;
import std.stdio, std.array, std.algorithm, std.bigint, std.range;
string spellInteger(in long n) pure nothrow {
static immutable tens = ["", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"];
immutable tens = ["", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"];
immutable small = ["zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"];
immutable huge = ["", ""] ~ ["m", "b", "tr", "quadr", "quint",
"sext", "sept", "oct", "non", "dec"]
.map!q{ a ~ "illion" }.array;
static immutable small = "zero one two three four five six
seven eight nine ten eleven twelve thirteen fourteen
fifteen sixteen seventeen eighteen nineteen".split();
static immutable bl = ["", "", "m", "b", "tr",
"quadr", "quint", "sext", "sept", "oct", "non", "dec"];
static string nonZero(in string c, in int n) pure nothrow {
return n == 0 ? "" : c ~ spellInteger(n);
string spellBigInt(BigInt n) {
static string nonZero(string c, BigInt n, string connect="") {
return n == 0 ? "" : connect ~ c ~ n.spellBigInt;
}
static string big(in int e, in int n) pure nothrow {
static string lastAnd(string num) {
if (num.canFind(",")) {
string pre = num.retro.find(",").retro[0 .. $ - 1];
string last = num[pre.length + 1 .. $];
if (!last.canFind(" and "))
last = " and" ~ last;
num = pre ~ "," ~ last;
}
return num;
}
static string big(in uint e, BigInt n) {
switch (e) {
case 0: return spellInteger(n);
case 1: return spellInteger(n) ~ " thousand";
default: return spellInteger(n) ~ " " ~ bl[e] ~ "illion";
case 0: return n.spellBigInt;
case 1: return n.spellBigInt ~ " thousand";
default: return n.spellBigInt ~ " " ~ huge[e];
}
}
/// Generates the value of the digits of n in
/// base 1000 (i.e. 3-digit chunks), in reverse.
static int[] base1000Reverse(in long nn) pure nothrow {
long n = nn;
int[] result;
while (n) {
result ~= n % 1000;
n /= 1000;
}
return result;
}
if (n < 0) {
return "negative " ~ spellInteger(-n);
return "minus " ~ spellBigInt(-n);
} else if (n < 20) {
return small[n.toInt];
} else if (n < 100) {
BigInt a = n / 10;
BigInt b = n % 10;
return tens[a.toInt] ~ nonZero("-", b);
} else if (n < 1000) {
int ni = cast(int)n; // D doesn't infer this.
if (ni < 20) {
return small[ni];
} else if (ni < 100) {
return tens[ni / 10] ~ nonZero("-", ni % 10);
} else // ni < 1000
return small[ni / 100] ~ " hundred" ~
nonZero(" ", ni % 100);
BigInt a = n / 100;
BigInt b = n % 100;
return small[a.toInt] ~ " hundred" ~ nonZero(" ", b, " and");
} else {
string[] pieces;
foreach_reverse (e, x; base1000Reverse(n))
pieces ~= big(e, x);
return pieces.join(", ");
string[] bigs;
uint e = 0;
while (n != 0) {
BigInt r = n % 1000;
n /= 1000;
if (r != 0)
bigs ~= big(e, r);
e++;
}
return lastAnd(bigs.retro.join(", "));
}
}
void main() {
foreach (i; -10 .. 1_000)
writeln(i, " ", spellInteger(i));
version(number_names_main) {
void main() {
foreach (n; [0, -3, 5, -7, 11, -13, 17, -19, 23, -29])
writefln("%+4d -> %s", n, n.BigInt.spellBigInt);
writeln;
auto n = 2_0121_002_001;
while (n) {
writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
n /= -10;
}
writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
writeln;
}
}

View file

@ -1,48 +1,64 @@
TENS = [None, None, "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"]
SMALL = ["zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"]
HUGE = [None, None] + [h + "illion"
for h in ("m", "b", "tr", "quadr", "quint", "sext",
"sept", "oct", "non", "dec")]
def nonzero(c, n, connect=''):
return "" if n == 0 else connect + c + spell_integer(n)
def last_and(num):
if ',' in num:
pre, last = num.rsplit(',', 1)
if ' and ' not in last:
last = ' and' + last
num = ''.join([pre, ',', last])
return num
def big(e, n):
if e == 0:
return spell_integer(n)
elif e == 1:
return spell_integer(n) + " thousand"
else:
return spell_integer(n) + " " + HUGE[e]
def base1000_rev(n):
# generates the value of the digits of n in base 1000
# (i.e. 3-digit chunks), in reverse.
while n != 0:
n, r = divmod(n, 1000)
yield r
def spell_integer(n):
tens = [None, None, "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"]
small = ["zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"]
bl = [None, None, "m", "b", "tr", "quadr",
"quint", "sext", "sept", "oct", "non", "dec"]
def nonzero(c, n):
return "" if n == 0 else c + spell_integer(n)
def big(e, n):
if e == 0:
return spell_integer(n)
elif e == 1:
return spell_integer(n) + " thousand"
else:
return spell_integer(n) + " " + bl[e] + "illion"
def base1000_rev(n):
# generates the value of the digits of n in base 1000
# (i.e. 3-digit chunks), in reverse.
while n != 0:
n, r = divmod(n, 1000)
yield r
if n < 0:
return "negative " + spell_integer(-n)
return "minus " + spell_integer(-n)
elif n < 20:
return small[n]
return SMALL[n]
elif n < 100:
a, b = divmod(n, 10)
return tens[a] + nonzero("-", b)
return TENS[a] + nonzero("-", b)
elif n < 1000:
a, b = divmod(n, 100)
return small[a] + " hundred" + nonzero(" ", b)
return SMALL[a] + " hundred" + nonzero(" ", b, ' and')
else:
return ", ".join([big(e, x) for e, x in
enumerate(base1000_rev(n)) if x][::-1])
num = ", ".join([big(e, x) for e, x in
enumerate(base1000_rev(n)) if x][::-1])
return last_and(num)
# example
print spell_integer(1278)
print spell_integer(1752)
print spell_integer(2010)
if __name__ == '__main__':
# examples
for n in (0, -3, 5, -7, 11, -13, 17, -19, 23, -29):
print('%+4i -> %s' % (n, spell_integer(n)))
print('')
n = 201021002001
while n:
print('%-12i -> %s' % (n, spell_integer(n)))
n //= -10
print('%-12i -> %s' % (n, spell_integer(n)))
print('')

View file

@ -0,0 +1,37 @@
#lang racket
(define smalls
(map symbol->string
'(zero one two three four five six seven eight nine ten eleven twelve
thirteen fourteen fifteen sixteen seventeen eighteen nineteen)))
(define tens
(map symbol->string
'(zero ten twenty thirty forty fifty sixty seventy eighty ninety)))
(define larges
(map symbol->string
'(thousand million billion trillion quadrillion quintillion sextillion
septillion octillion nonillion decillion undecillion duodecillion
tredecillion quattuordecillion quindecillion sexdecillion
septendecillion octodecillion novemdecillion vigintillion)))
(define (integer->english n)
(define (step div suffix separator [subformat integer->english])
(define-values [q r] (quotient/remainder n div))
(define S (if suffix (~a (subformat q) " " suffix) (subformat q)))
(if (zero? r) S (~a S separator (integer->english r))))
(cond [(< n 0) (~a "negative " (integer->english (- n)))]
[(< n 20) (list-ref smalls n)]
[(< n 100) (step 10 #f "-" (curry list-ref tens))]
[(< n 1000) (step 100 "hundred" " and ")]
[else (let loop ([N 1000000] [D 1000] [unit larges])
(cond [(null? unit)
(error 'integer->english "number too big: ~e" n)]
[(< n N) (step D (car unit) ", ")]
[else (loop (* 1000 N) (* 1000 D) (cdr unit))]))]))
(for ([n 10])
(define e (expt 10 n))
(define r (+ (* e (random e)) (random e)))
(printf "~s: ~a\n" r (integer->english r)))

View file

@ -0,0 +1,69 @@
/**
* Spells a number longhand
*
* @example longhand( 1234 ) // results in: one thousand two hundred thirty-four
*/
def longhand( v:Long, showAnd:Boolean = false, showHyphen:Boolean = true ) : String = {
// Based on a solution of Rex Kerr's
val onesAndTeens = {
val a1 = Array[String]("")
val a2 = "one two three four five six seven eight nine ten eleven twelve".split(' ').map(_ + " ")
val a3 = "thir four fif six seven eigh nine".split(' ').map(_ + "teen ")
a1 ++ a2 ++ a3
}
val tens = {
val a1 = Array[String]("","")
val a2 = "twen thir for fif six seven eigh nine".split(' ').map(_ + "ty")
a1 ++ a2
}
val hundredString = "hundred "
val andString = if( showAnd ) "and " else ""
val hyphenString = if( showHyphen ) "-" else " "
val powersOfThousands = {
val a1 = Array[String]("","thousand ")
val a2 = "m b tr quadr quint sext sept oct non dec".split(' ').map(_ + "illion ")
val a3 = "un duo tre quattuor quin sex septen octo novem ".split(' ').map(_ + "decillion ")
val a4 = "vigint cent".split(' ').map(_ + "illion ")
a1 ++ a2 ++ a3 ++ a4
}
// 234 becomes "two hundred [and] thirty-four"
def composeScale( v:String, isFirst:Boolean ) : String = {
val e1 = (v.map(_.toString.toInt).reverse zip List("","-","hundred")).reverse
e1.map {
case (d,"hundred") if d > 0 => onesAndTeens(d) + hundredString + andString
case (d,"-") if d > 1 && !e1.contains((0,"")) && isFirst => tens(d) + hyphenString
case (d,"-") if d > 1 && !e1.contains((0,"")) => tens(d) + " "
case (d,"-") if d > 1 => tens(d)
case (d,"") if e1.contains((1,"-")) => onesAndTeens(d+10)
case (d,"") => onesAndTeens(d)
case _ => ""
}.mkString
}
def compose( s:String ) : String = {
// "1234" becomes List(((1,false),"thousand"), ((234,true),""))
val thousands = {
def first( s:String ) = (true) #:: Stream.continually(false) // First element true others false
val e1 = s.reverse.grouped(3).map(_.reverse).toList // Group into powers of thousands
val e2 = e1 zip first(s) // Mark the first element
val e3 = e2 zip powersOfThousands // Name the powers of Thousands
e3.reverse // Put it back to most-significant first
}
thousands.map { case ((v,isFirst),s) => composeScale( v, isFirst ) + s }.mkString.trim
}
if( v < 0 ) "minus " + compose((-v).toString) else compose(v.toString)
}
// A little test...
println( Long.MaxValue-13 + " is \"" + longhand( Long.MaxValue-13 ) + "\"" )