问题
Okay. So I'm wondering how to create a function that will turn a random number into its english word component.
Such as (1001 -> '(one thousand one) or 0 -> '(zero) and (number-name factorial 20 -> ’(two quintillion four hundred thirty two quadrillion nine hundred two trillion eight billion one hundred seventy six million six hundred forty thousand))
I worked with a previous user on stackoverflow to get something that turned a long number into 3 part digits (1,341,100 is one million, 341 thousand 1 hundred 0 tens 0 ones)
#lang r5rs
(define (three-names n)
(if (zero? n)
"zero"
(let loop ((n n)
(units '((10 one) (10 ten) (10 hundred) (1000 thousand) (1000 million) (1000 billion) (1000 trillion) (1000 quadrillion) (1000 quintillion)
(1000 sextillion) (1000 septillion) (1000 octillion) (1000 nonillion)
(1000 decillion) (1000 undecillion) (1000 duodecillion) (1000 tredecillion)
(1000 quatturodecillion) (1000 sexdillion) (1000 septendecillion) (1000 octodecillion)
(1000 novemdecillion) (1000 vigintillion)))
(ARRAY '()))
(if
(or (zero? n) (null? units))
ARRAY
(let* ((unit (car units)) (div (car unit)) (english (cadr unit)))
(let
((q (quotient n div)) (r (remainder n div)))
(loop q
(cdr units)
(cons r (cons english ARRAY)))))))))
The only thing I understand right now is to make it so that there are values for 0-20:
(= x 0) zero
(= x 1) one
...
(> x 1000) thousand
(> x 1000000) million
But for one, these won't be outputted into a list and two, not sure what else to do?
回答1:
As Sylwester explains you need to be able to
- correctly print the text for every number below 1000 (3 digits)
- divide the number in 3-digits groups, print them using above code and just append the "thousands" suffices
Here's an example implementation that is compatible with Racket's r5rs language:
(define (n2t n)
(define 1to19 '(one two three four five six seven eight nine ten eleven twelve
thirteen fourteen fifteen sixteen seventeen eighteen nineteen))
(define multof10 '(twenty thirty forty fifty sixty seventy eighty ninety))
(define thousands '(thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion undecillion))
(cond
((= n 0) '(zero)) ; zero is a special case since from now on all 0 will be suppressed
((< n 0) (cons 'minus (n2t (- n))))
(else
(let loop ((n n) (units thousands) (res '()))
(cond
; --- below 1000
((= n 0) res)
((< 0 n 20) (cons (list-ref 1to19 (- n 1)) res))
((< n 100) (cons (list-ref multof10 (- (quotient n 10) 2))
(loop (remainder n 10) '() res)))
((< n 1000) (loop (quotient n 100)
'()
(cons 'hundred (loop (remainder n 100) '() res))))
(else
; --- 1000 and above
(let ((q (quotient n 1000))
(res (loop (remainder n 1000) thousands res)))
(if (zero? q)
res
(loop q (cdr units) (cons (car units) res))))))))))
Testing:
> (n2t 0)
'(zero)
> (n2t 1001)
'(one thousand one)
> (n2t 132219)
'(one hundred thirty two thousand two hundred nineteen)
> (n2t -132219)
'(minus one hundred thirty two thousand two hundred nineteen)
> (n2t 2345678213)
'(two billion three hundred forty five million six hundred seventy eight thousand two hundred thirteen)
> (n2t 2432902008176640000)
'(two quintillion four hundred thirty two quadrillion nine hundred two trillion eight billion one hundred seventy six million six hundred forty thousand)
回答2:
As you probably know you should be able to do something like:
(number->english 2345678213)
; ==> "two billion three hundred and fourtyfive million six \
; hundred and seventyeight tousand two hundred and thirteen"
At first glimse you can see that there is a pattern:
...
<english number text below 1000> million
<english number text below 1000> thousand
<english number text below 1000>
Thus.. the procedure would perhaps look something like:
(define (number->english x)
(if (zero? x)
"zero"
(iterate-thousands x thousands '()))
with thousands
being defined as: '("" "thousand" "million" "billion" "trillion" ...)
and iterate-tousands
perhaps look something like this:
(define (iterate-thousands thousands x acc)
(if (zero? x)
(join acc " ")
(iterate-thousands (cdr thousands)
(quotient x 1000)
(list* (below-1000 (remainder x 1000))
(car thousands)
acc))))
Where below-1000
returns a correct string for every number below 1000. It would typically divide the work according to the naming convention. That is something special for below 13, the teens until 19, compound the ty + ones until 99 and perhaps a recursion on the above that takes ones + " hundred " + recursion on the remainder so that 234
becomes (string-append "two hundred and " (below-1000 34))
. join
just use string-append
with separator and handles empty strings correctly.
来源:https://stackoverflow.com/questions/35666978/scheme-number-english-list