utils.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. export const chainPromises = <T>(
  2. promises: Promise<T>[],
  3. reducer = (p1: Promise<T>, p2: Promise<T>) => p1.then(() => p2),
  4. initialValue?: T
  5. ) => promises.reduce(reducer, Promise.resolve(initialValue));
  6. const splitBigNumAt = (num: string, at: number) => num.replace(RegExp(String.raw`^([+-]?)(\d+)(\d{${at}})$`), '$1$2,$1$3')
  7. .replace(/^([^,]*)$/, '0,$1').split(',')
  8. .map(Number);
  9. const bigNumPlus = (num1: string, num2: string) => {
  10. let [high, low] = [splitBigNumAt(num1, 15), splitBigNumAt(num2, 15)]
  11. .reduce((a, b) => [a[0] + b[0], a[1] + b[1]]);
  12. const [highSign, lowSign] = [high, low].map(Math.sign);
  13. if (highSign === 0) return low.toString();
  14. if (highSign + lowSign === 0) {
  15. [high, low] = [high - highSign, low - lowSign * 10 ** 15];
  16. } else {
  17. [high, low] = [high + Math.trunc(low / 10 ** 15), low % 10 ** 15];
  18. }
  19. if (high === 0) return low.toString();
  20. return `${high}${Math.abs(low).toString().padStart(15, '0')}`;
  21. };
  22. const bigNumCompare = (num1: string, num2: string) => Math.sign(Number(bigNumPlus(
  23. num1,
  24. num2.replace(/^([+-]?)(\d+)/, (_, $1, $2) => `${$1 === '-' ? '' : '-'}${$2}`)
  25. )));
  26. const bigNumMin = (...nums: string[]) => {
  27. if (!nums || !nums.length) return undefined;
  28. let min = nums[0];
  29. for (let i = 1; i < nums.length; i++) {
  30. if (bigNumCompare(nums[i], min) < 0) min = nums[i];
  31. }
  32. return min;
  33. };
  34. const bigNumLShift = (num: string, by: number) => {
  35. if (by < 0) throw Error('cannot perform right shift');
  36. const at = Math.trunc((52 - by) / 10) * 3;
  37. const [high, low] = splitBigNumAt(num, at).map(n => n * 2 ** by);
  38. return bigNumPlus(`${high}${'0'.repeat(at)}`, low.toString());
  39. };
  40. const parseBigNum = (str: string) => (/^-?\d+$/.exec(str) || [''])[0].replace(/^(-)?0*/, '$1');
  41. export const BigNumOps = {
  42. splitAt: splitBigNumAt,
  43. plus: bigNumPlus,
  44. compare: bigNumCompare,
  45. min: bigNumMin,
  46. lShift: bigNumLShift,
  47. parse: parseBigNum,
  48. };