(ns auto-ap.numeric (:require [clojure.string :as str])) (def ^:private smalls ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen"]) (def ^:private tens ["twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety"]) (def ^:private magnitudes ["thousand" "million" "billion" "trillion" "quadrillion" "quintillion" "sextillion" "septillion" "octillion" "nonillion" "decillion" "undecillion" "duodecillion" "tredecillion" "quattuordecillion" "quindecillion" "quinquadecillion" "sexdecillion" "sedecillion" "septendecillion" "octodecillion" "novemdecillion" "novendecillion" "vigintillion" #_"centillion"]) (defn words [n] {:pre [(not (neg? n))]} (cond (< n 20) (smalls n) (< n 100) (let [pre (tens (- (quot n 10) 2)), x (rem n 10)] (if (zero? x) pre (str pre "-" (words x)))) (< n 1000) (let [hun (quot n 100), x (rem n 100), s (str (words hun) " hundred")] (if (zero? x) s (str s " and " (words x)))) :else (loop [parts [] n n mag -1] (if (zero? n) (str/join " " parts) (let [x (rem n 1000) n (quot n 1000) parts (if (zero? x) parts (let [s (words x)] (cons (if (neg? mag) (if (< x 100) (str "and " s) s) (str s " " (magnitudes mag))) parts)))] (recur parts n (inc mag))))))) (defn num->words [num] (let [total-cents (int (* 100 num)) dollar-num (int (quot total-cents 100)) cent-num (int (rem total-cents 100)) dollars (str (words dollar-num) " dollars") cents (str (words cent-num) " cents")] (cond (and (> dollar-num 0) (> cent-num 0)) (str dollars " and " cents) (> dollar-num 0) dollars :else cents)))