Gets the name of a number, even if it's stupidly big. Supersedes TheoryOfNekomata/number-name.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

en-US.test.ts 11 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import { describe, it, expect } from 'vitest';
  2. import { parse, stringify, systems } from '../../src';
  3. import { numberToExponential } from '../../src/exponent';
  4. const options = {
  5. system: systems.enUS.shortCount,
  6. };
  7. const stringifyOptions = {
  8. ...options,
  9. stringifyGroupsOptions: {
  10. addTensDashes: false,
  11. },
  12. };
  13. describe('numerica', () => {
  14. describe('group names', () => {
  15. describe('0-9', () => {
  16. it.each`
  17. ones | expected
  18. ${0} | ${'zero'}
  19. ${1} | ${'one'}
  20. ${2} | ${'two'}
  21. ${3} | ${'three'}
  22. ${4} | ${'four'}
  23. ${5} | ${'five'}
  24. ${6} | ${'six'}
  25. ${7} | ${'seven'}
  26. ${8} | ${'eight'}
  27. ${9} | ${'nine'}
  28. `('converts $ones to $expected', ({ ones, expected }: { ones: number, expected: string }) => {
  29. expect(stringify(ones, stringifyOptions)).toBe(expected);
  30. expect(parse(expected, { ...options, type: 'number' })).toBe(ones);
  31. });
  32. });
  33. describe('10-19', () => {
  34. it.each`
  35. tenPlusOnes | expected
  36. ${10} | ${'ten'}
  37. ${11} | ${'eleven'}
  38. ${12} | ${'twelve'}
  39. ${13} | ${'thirteen'}
  40. ${14} | ${'fourteen'}
  41. ${15} | ${'fifteen'}
  42. ${16} | ${'sixteen'}
  43. ${17} | ${'seventeen'}
  44. ${18} | ${'eighteen'}
  45. ${19} | ${'nineteen'}
  46. `('converts $tenPlusOnes to $expected', ({ tenPlusOnes, expected }: { tenPlusOnes: number, expected: string }) => {
  47. expect(stringify(tenPlusOnes, stringifyOptions)).toBe(expected);
  48. expect(parse(expected, { ...options, type: 'number' })).toBe(tenPlusOnes);
  49. });
  50. });
  51. describe.each`
  52. tensStart | tensEnd | tensBase
  53. ${20} | ${29} | ${'twenty'}
  54. ${30} | ${39} | ${'thirty'}
  55. ${40} | ${49} | ${'forty'}
  56. ${50} | ${59} | ${'fifty'}
  57. ${60} | ${69} | ${'sixty'}
  58. ${70} | ${79} | ${'seventy'}
  59. ${80} | ${89} | ${'eighty'}
  60. ${90} | ${99} | ${'ninety'}
  61. `('$tensStart-$tensEnd', ({
  62. tensStart, tensBase,
  63. }: { tensStart: number, tensBase: string }) => {
  64. it.each`
  65. value | expected
  66. ${tensStart} | ${tensBase}
  67. ${tensStart + 1} | ${`${tensBase} one`}
  68. ${tensStart + 2} | ${`${tensBase} two`}
  69. ${tensStart + 3} | ${`${tensBase} three`}
  70. ${tensStart + 4} | ${`${tensBase} four`}
  71. ${tensStart + 5} | ${`${tensBase} five`}
  72. ${tensStart + 6} | ${`${tensBase} six`}
  73. ${tensStart + 7} | ${`${tensBase} seven`}
  74. ${tensStart + 8} | ${`${tensBase} eight`}
  75. ${tensStart + 9} | ${`${tensBase} nine`}
  76. `('converts $value to $expected', ({ value, expected }: { value: number, expected: string }) => {
  77. expect(stringify(value, stringifyOptions)).toBe(expected);
  78. expect(parse(expected, { ...options, type: 'number' })).toBe(value);
  79. });
  80. });
  81. describe.each`
  82. hundredsStart | hundredsEnd | hundredsBase
  83. ${100} | ${199} | ${'one hundred'}
  84. ${200} | ${299} | ${'two hundred'}
  85. ${300} | ${399} | ${'three hundred'}
  86. ${400} | ${499} | ${'four hundred'}
  87. ${500} | ${599} | ${'five hundred'}
  88. ${600} | ${699} | ${'six hundred'}
  89. ${700} | ${799} | ${'seven hundred'}
  90. ${800} | ${899} | ${'eight hundred'}
  91. ${900} | ${999} | ${'nine hundred'}
  92. `('$hundredsStart-$hundredsEnd', ({
  93. hundredsStart, hundredsBase,
  94. }: { hundredsStart: number, hundredsBase: string }) => {
  95. describe(`${hundredsStart}-${hundredsStart + 9}`, () => {
  96. it.each`
  97. value | expected
  98. ${hundredsStart} | ${hundredsBase}
  99. ${hundredsStart + 1} | ${`${hundredsBase} one`}
  100. ${hundredsStart + 2} | ${`${hundredsBase} two`}
  101. ${hundredsStart + 3} | ${`${hundredsBase} three`}
  102. ${hundredsStart + 4} | ${`${hundredsBase} four`}
  103. ${hundredsStart + 5} | ${`${hundredsBase} five`}
  104. ${hundredsStart + 6} | ${`${hundredsBase} six`}
  105. ${hundredsStart + 7} | ${`${hundredsBase} seven`}
  106. ${hundredsStart + 8} | ${`${hundredsBase} eight`}
  107. ${hundredsStart + 9} | ${`${hundredsBase} nine`}
  108. `('converts $value to $expected', ({ value, expected }: { value: number, expected: string }) => {
  109. expect(stringify(value, stringifyOptions)).toBe(expected);
  110. expect(parse(expected, { ...options, type: 'number' })).toBe(value);
  111. });
  112. });
  113. describe(`${hundredsStart + 10}-${hundredsStart + 19}`, () => {
  114. it.each`
  115. value | expected
  116. ${hundredsStart + 10} | ${`${hundredsBase} ten`}
  117. ${hundredsStart + 11} | ${`${hundredsBase} eleven`}
  118. ${hundredsStart + 12} | ${`${hundredsBase} twelve`}
  119. ${hundredsStart + 13} | ${`${hundredsBase} thirteen`}
  120. ${hundredsStart + 14} | ${`${hundredsBase} fourteen`}
  121. ${hundredsStart + 15} | ${`${hundredsBase} fifteen`}
  122. ${hundredsStart + 16} | ${`${hundredsBase} sixteen`}
  123. ${hundredsStart + 17} | ${`${hundredsBase} seventeen`}
  124. ${hundredsStart + 18} | ${`${hundredsBase} eighteen`}
  125. ${hundredsStart + 19} | ${`${hundredsBase} nineteen`}
  126. `('converts $value to $expected', ({ value, expected }: { value: number, expected: string }) => {
  127. expect(stringify(value, stringifyOptions)).toBe(expected);
  128. expect(parse(expected, { ...options, type: 'number' })).toBe(value);
  129. });
  130. });
  131. describe.each`
  132. start | end | base
  133. ${20} | ${29} | ${'twenty'}
  134. ${30} | ${39} | ${'thirty'}
  135. ${40} | ${49} | ${'forty'}
  136. ${50} | ${59} | ${'fifty'}
  137. ${60} | ${69} | ${'sixty'}
  138. ${70} | ${79} | ${'seventy'}
  139. ${80} | ${89} | ${'eighty'}
  140. ${90} | ${99} | ${'ninety'}
  141. `('$start-$end', ({
  142. start, base,
  143. }: { start: number, base: string }) => {
  144. it.each`
  145. value | expected
  146. ${hundredsStart + start} | ${`${hundredsBase} ${base}`}
  147. ${hundredsStart + start + 1} | ${`${hundredsBase} ${base} one`}
  148. ${hundredsStart + start + 2} | ${`${hundredsBase} ${base} two`}
  149. ${hundredsStart + start + 3} | ${`${hundredsBase} ${base} three`}
  150. ${hundredsStart + start + 4} | ${`${hundredsBase} ${base} four`}
  151. ${hundredsStart + start + 5} | ${`${hundredsBase} ${base} five`}
  152. ${hundredsStart + start + 6} | ${`${hundredsBase} ${base} six`}
  153. ${hundredsStart + start + 7} | ${`${hundredsBase} ${base} seven`}
  154. ${hundredsStart + start + 8} | ${`${hundredsBase} ${base} eight`}
  155. ${hundredsStart + start + 9} | ${`${hundredsBase} ${base} nine`}
  156. `('converts $value to $expected', ({ value, expected }: { value: number, expected: string }) => {
  157. expect(stringify(value, stringifyOptions)).toBe(expected);
  158. expect(parse(expected, { ...options, type: 'number' })).toBe(value);
  159. });
  160. });
  161. });
  162. });
  163. it('converts 1000 to one thousand', () => {
  164. expect(stringify(1000, stringifyOptions)).toBe('one thousand');
  165. expect(parse('one thousand', { ...options, type: 'number' })).toBe(1000);
  166. });
  167. it('converts 10000 to ten thousand', () => {
  168. expect(stringify(10000, stringifyOptions)).toBe('ten thousand');
  169. expect(parse('ten thousand', { ...options, type: 'number' })).toBe(10000);
  170. });
  171. it('converts 100000 to one hundred thousand', () => {
  172. expect(stringify(100000, stringifyOptions)).toBe('one hundred thousand');
  173. expect(parse('one hundred thousand', { ...options, type: 'number' })).toBe(100000);
  174. });
  175. it('converts 123456 to one hundred twenty three thousand four hundred fifty six', () => {
  176. expect(stringify(123456, stringifyOptions)).toBe('one hundred twenty three thousand four hundred fifty six');
  177. expect(parse('one hundred twenty three thousand four hundred fifty six', { ...options, type: 'number' })).toBe(123456);
  178. });
  179. it.each`
  180. value | expected
  181. ${1e+6} | ${'one million'}
  182. ${1e+9} | ${'one billion'}
  183. ${1e+12} | ${'one trillion'}
  184. ${1e+15} | ${'one quadrillion'}
  185. ${1e+18} | ${'one quintillion'}
  186. ${1e+21} | ${'one sextillion'}
  187. ${1e+24} | ${'one septillion'}
  188. ${1e+27} | ${'one octillion'}
  189. ${1e+30} | ${'one nonillion'}
  190. `('converts $value to $expected', ({ value, expected }: { value: number, expected: string }) => {
  191. expect(stringify(value, stringifyOptions)).toBe(expected);
  192. expect(parse(expected, { ...options, type: 'number' })).toBe(value);
  193. });
  194. it.each`
  195. value | expected
  196. ${'1e+33'} | ${'one decillion'}
  197. ${'1e+36'} | ${'one undecillion'}
  198. ${'1e+39'} | ${'one duodecillion'}
  199. ${'1e+42'} | ${'one tredecillion'}
  200. ${'1e+45'} | ${'one quattuordecillion'}
  201. ${'1e+48'} | ${'one quindecillion'}
  202. ${'1e+51'} | ${'one sexdecillion'}
  203. ${'1e+54'} | ${'one septendecillion'}
  204. ${'1e+57'} | ${'one octodecillion'}
  205. ${'1e+60'} | ${'one novemdecillion'}
  206. `('converts $value to $expected', ({ value, expected }: { value: string, expected: string }) => {
  207. expect(stringify(value, stringifyOptions)).toBe(expected);
  208. expect(parse(expected, options)).toBe(value);
  209. });
  210. it.each`
  211. value | expected
  212. ${'1e+63'} | ${'one vigintillion'}
  213. ${'1e+66'} | ${'one unvigintillion'}
  214. ${'1e+69'} | ${'one duovigintillion'}
  215. ${'1e+72'} | ${'one trevigintillion'}
  216. ${'1e+75'} | ${'one quattuorvigintillion'}
  217. ${'1e+78'} | ${'one quinvigintillion'}
  218. ${'1e+81'} | ${'one sexvigintillion'}
  219. ${'1e+84'} | ${'one septenvigintillion'}
  220. ${'1e+87'} | ${'one octovigintillion'}
  221. ${'1e+90'} | ${'one novemvigintillion'}
  222. `('converts $value to $expected', ({ value, expected }: { value: string, expected: string }) => {
  223. expect(stringify(value, stringifyOptions)).toBe(expected);
  224. expect(parse(expected, options)).toBe(value);
  225. });
  226. it.each`
  227. value | expected
  228. ${'1e+93'} | ${'one trigintillion'}
  229. ${'1e+123'} | ${'one quadragintillion'}
  230. ${'1e+153'} | ${'one quinquagintillion'}
  231. ${'1e+183'} | ${'one sexagintillion'}
  232. ${'1e+213'} | ${'one septuagintillion'}
  233. ${'1e+243'} | ${'one octogintillion'}
  234. ${'1e+273'} | ${'one nonagintillion'}
  235. `('converts $value to $expected', ({ value, expected }: { value: string, expected: string }) => {
  236. expect(stringify(value, stringifyOptions)).toBe(expected);
  237. expect(parse(expected, options)).toBe(value);
  238. });
  239. it('converts values', () => {
  240. const exp1 = numberToExponential('123,456,789,012,345,678,901,234,567,890');
  241. //
  242. // one hundred twenty three octillion
  243. // four hundred fifty six septillion
  244. // seven hundred eighty nine sextillion
  245. // twelve quintillion
  246. // three hundred forty five quadrillion
  247. // six hundred seventy eight trillion
  248. // nine hundred one billion
  249. // two hundred thirty four million
  250. // five hundred sixty seven thousand
  251. // eight hundred ninety
  252. expect(parse(stringify('123456789012345678901234567890'))).toBe(exp1);
  253. const value2 = '1000005000000';
  254. const exp2 = numberToExponential(value2);
  255. expect(stringify(value2)).toBe('one trillion five million');
  256. expect(parse(stringify(value2))).toBe(exp2);
  257. const value3 = '12012';
  258. const exp3 = numberToExponential(value3);
  259. expect(stringify(value3)).toBe('twelve thousand twelve');
  260. expect(parse(stringify(value3))).toBe(exp3);
  261. const value4 = '12020';
  262. const exp4 = numberToExponential(value4);
  263. expect(stringify(value4)).toBe('twelve thousand twenty');
  264. expect(parse(stringify(value4))).toBe(exp4);
  265. const value5 = '1e3006';
  266. expect(stringify(value5)).toBe('one milliauntillion');
  267. });
  268. it('converts short millia', () => {
  269. const shortMillia1 = 'one millia^1-tillion';
  270. expect(parse(shortMillia1)).toBe('1e+3003');
  271. const shortMillia2 = 'one millia^2-tillion';
  272. expect(parse(shortMillia2)).toBe('1e+3000003');
  273. expect(stringify(parse(shortMillia2), { stringifyGroupsOptions: { shortenMillia: true } }))
  274. .toBe(shortMillia2);
  275. });
  276. });