55 lines
2 KiB
Racket
55 lines
2 KiB
Racket
#lang racket
|
|
|
|
(require rackunit)
|
|
|
|
(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 (number->words n)
|
|
(define (step div suffix separator [subformat number->words])
|
|
(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 (number->words r))))
|
|
(cond [(< n 0) (~a "negative " (number->words (- n)))]
|
|
[(< n 20) (list-ref smalls n)]
|
|
[(< n 100) (step 10 #f "-" (curry list-ref tens))]
|
|
[(< n 1000) (step 100 "hundred" " ")]
|
|
[else (let loop ([N 1000000] [D 1000] [unit larges])
|
|
(cond [(null? unit)
|
|
(error 'number->words "number too big: ~e" n)]
|
|
[(< n N) (step D (car unit) " ")]
|
|
[else (loop (* 1000 N) (* 1000 D) (cdr unit))]))]))
|
|
|
|
(define (first-cap s)
|
|
(~a (string-upcase (substring s 0 1)) (substring s 1)))
|
|
|
|
(define (magic word [acc null])
|
|
(if (equal? word "four")
|
|
(string-join (reverse (cons "four is magic." acc)) ", \n")
|
|
(let* ([word-len (string-length word)]
|
|
[words (number->words word-len)])
|
|
(magic words
|
|
(cons (string-append word " is " words) acc)))))
|
|
|
|
(define (number-magic n)
|
|
(first-cap (magic (number->words n))))
|
|
|
|
(for ([n (append (range 11)
|
|
'(-10 23 172 20140 100 130 999999 876000000
|
|
874143425855745733896030))])
|
|
(displayln n)
|
|
(displayln (number-magic n))
|
|
(newline))
|