Gets the name of a number, even if it's stupidly big. Supersedes TheoryOfNekomata/number-name.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

77 řádky
2.6 KiB

  1. import BigNumber from 'bignumber.js';
  2. const EXPONENT_SEPARATOR = 'e';
  3. const SIGNIFICAND_DECIMAL_POINT = '.';
  4. export const NEGATIVE_SIGN = '-';
  5. export const BLANK_DIGIT = '0'; // must be a value where Number(BLANK_DIGIT) === 0
  6. export type Numeric = number | bigint | string | BigNumber
  7. export type Group = [string, BigNumber]
  8. export const normalizeNumeric = (x: Numeric): string => {
  9. try {
  10. switch (typeof x) {
  11. case 'number':
  12. return new BigNumber(x).toString(10);
  13. case 'bigint':
  14. return x.toString(10);
  15. case 'string':
  16. // TODO assume not all strings follow a correct format
  17. return x.trim();
  18. // return new BigNumber(x).toString(10)
  19. case 'object':
  20. return x.toString(10);
  21. default:
  22. break;
  23. }
  24. } catch {
  25. throw new RangeError('Not a valid numeric value in the current locale.');
  26. }
  27. throw new TypeError('Not a valid numeric value in any locale.');
  28. };
  29. export const deconstructNumeric = (x: string) => {
  30. const absolute = x.replaceAll(NEGATIVE_SIGN, '');
  31. if (!absolute.includes(EXPONENT_SEPARATOR)) {
  32. return {
  33. exponent: new BigNumber(absolute.length - 1),
  34. significandDigits: absolute,
  35. };
  36. }
  37. const [significandStrExp, exponentStr] = absolute.split(EXPONENT_SEPARATOR);
  38. const [integral] = significandStrExp.split(SIGNIFICAND_DECIMAL_POINT);
  39. return {
  40. exponent: new BigNumber(exponentStr).plus(integral.length - 1),
  41. significandDigits: significandStrExp.replaceAll(SIGNIFICAND_DECIMAL_POINT, ''),
  42. };
  43. };
  44. export const createBlankDigits = (grouping: number) => new Array<string>(grouping).fill(BLANK_DIGIT).join('');
  45. export const groupDigits = (significandStr: string, exponent: BigNumber, grouping: number) => {
  46. const blankDigits = createBlankDigits(grouping);
  47. return significandStr
  48. .split('')
  49. .reduceRight(
  50. (theGroups, c, i): any => {
  51. const currentGroupIndex = exponent.minus(i).dividedToIntegerBy(grouping).minus(1);
  52. const [lastGroup = [blankDigits, currentGroupIndex.plus(1)] as Group] = theGroups;
  53. const [digits, groupIndex] = lastGroup;
  54. const currentPlaceValue = exponent.minus(i).mod(grouping);
  55. if (currentPlaceValue.eq(0)) {
  56. return [[`${blankDigits.slice(0, -c.length)}${c}`, currentGroupIndex.plus(1)], ...theGroups];
  57. }
  58. const currentDigitStringIndex = new BigNumber(grouping).minus(1).minus(currentPlaceValue).toNumber();
  59. const newDigits = digits.slice(
  60. 0,
  61. currentDigitStringIndex,
  62. ) + c + digits.slice(currentDigitStringIndex + c.length);
  63. return [[newDigits, groupIndex] as Group, ...theGroups.slice(1)];
  64. },
  65. [] as Group[],
  66. );
  67. };