├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src ├── absolute.ts ├── addition-digits.ts ├── addition.ts ├── common.ts ├── compare.ts ├── division-digits.ts ├── division.ts ├── factorial.ts ├── fizzbuzz-digits.ts ├── fizzbuzz.ts ├── index.ts ├── multiply-digits.ts ├── multiply.ts ├── negate.ts ├── power-digits.ts ├── power.ts ├── range.ts ├── substraction-digits.ts ├── substraction.ts └── test.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ecyrbe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ts-calc 2 | compute with typescript type system 3 | 4 | ![image](https://user-images.githubusercontent.com/633115/191343386-25f854d8-bdb3-43ba-9837-5a48d7ee5e77.png) 5 | 6 | 7 | 📦 ts-calc is now integrated in [HOTScript](https://github.com/gvergnaud/hotscript). 8 | 9 | You can compute almost anything with typescript type system. 10 | Unlike most example out there that use number to tuple trick, this is using new typescript 4.8 feature to convert strings to numbers or bigint. 11 | This allows to arbitrary long number computations that tuple trick can't do. 12 | This code base implement number and bigint for the following type functions: 13 | - addition 14 | - negation 15 | - absolute value 16 | - subtraction 17 | - comparison 18 | - multiplication 19 | - division 20 | - modulo 21 | - power 22 | - factorial 23 | - range 24 | - fizzbuzz 25 | 26 | enjoy! 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-calc", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "typescript": "^4.8.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/absolute.ts: -------------------------------------------------------------------------------- 1 | export type Absolute = 2 | `${T}` extends `-${infer U extends number | bigint}` ? U : T; 3 | -------------------------------------------------------------------------------- /src/addition-digits.ts: -------------------------------------------------------------------------------- 1 | import type { Digit } from "./common"; 2 | 3 | type AddDigitTable = [ 4 | [ 5 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 6 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], 7 | [2, 3, 4, 5, 6, 7, 8, 9, 0, 1], 8 | [3, 4, 5, 6, 7, 8, 9, 0, 1, 2], 9 | [4, 5, 6, 7, 8, 9, 0, 1, 2, 3], 10 | [5, 6, 7, 8, 9, 0, 1, 2, 3, 4], 11 | [6, 7, 8, 9, 0, 1, 2, 3, 4, 5], 12 | [7, 8, 9, 0, 1, 2, 3, 4, 5, 6], 13 | [8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 14 | [9, 0, 1, 2, 3, 4, 5, 6, 7, 8] 15 | ], 16 | [ 17 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], 18 | [2, 3, 4, 5, 6, 7, 8, 9, 0, 1], 19 | [3, 4, 5, 6, 7, 8, 9, 0, 1, 2], 20 | [4, 5, 6, 7, 8, 9, 0, 1, 2, 3], 21 | [5, 6, 7, 8, 9, 0, 1, 2, 3, 4], 22 | [6, 7, 8, 9, 0, 1, 2, 3, 4, 5], 23 | [7, 8, 9, 0, 1, 2, 3, 4, 5, 6], 24 | [8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 25 | [9, 0, 1, 2, 3, 4, 5, 6, 7, 8], 26 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 27 | ] 28 | ]; 29 | 30 | type AddDigitCarryTable = [ 31 | [ 32 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 33 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 34 | [0, 0, 0, 0, 0, 0, 0, 0, 1, 1], 35 | [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 36 | [0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 37 | [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], 38 | [0, 0, 0, 0, 1, 1, 1, 1, 1, 1], 39 | [0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 40 | [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 41 | [0, 1, 1, 1, 1, 1, 1, 1, 1, 1] 42 | ], 43 | [ 44 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 45 | [0, 0, 0, 0, 0, 0, 0, 0, 1, 1], 46 | [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 47 | [0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 48 | [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], 49 | [0, 0, 0, 0, 1, 1, 1, 1, 1, 1], 50 | [0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 51 | [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 52 | [0, 1, 1, 1, 1, 1, 1, 1, 1, 1], 53 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 54 | ] 55 | ]; 56 | 57 | type AddDigit< 58 | T extends Digit, 59 | U extends Digit, 60 | Carry extends 0 | 1 = 0 61 | > = AddDigitTable[Carry][T][U]; 62 | 63 | type AddCarryDigit< 64 | T extends Digit, 65 | U extends Digit, 66 | Carry extends 0 | 1 = 0 67 | > = AddDigitCarryTable[Carry][T][U]; 68 | 69 | export type AddDigits< 70 | T extends Digit[], 71 | U extends Digit[], 72 | Carry extends 0 | 1 = 0, 73 | Acc extends Digit[] = [] 74 | > = T extends [...infer R extends Digit[], infer N extends Digit] 75 | ? U extends [...infer S extends Digit[], infer M extends Digit] 76 | ? AddDigits< 77 | R, 78 | S, 79 | AddCarryDigit, 80 | [AddDigit, ...Acc] 81 | > 82 | : AddDigits< 83 | R, 84 | [], 85 | AddCarryDigit, 86 | [AddDigit, ...Acc] 87 | > 88 | : U extends [...infer S extends Digit[], infer M extends Digit] 89 | ? AddDigits< 90 | [], 91 | S, 92 | AddCarryDigit<0, M, Carry>, 93 | [AddDigit<0, M, Carry>, ...Acc] 94 | > 95 | : Carry extends 1 96 | ? [1, ...Acc] 97 | : Acc; 98 | -------------------------------------------------------------------------------- /src/addition.ts: -------------------------------------------------------------------------------- 1 | import { AddDigits } from "./addition-digits"; 2 | import type { 3 | ToNumber, 4 | ToString, 5 | Digit, 6 | DigitNumber, 7 | FromDigitNumber, 8 | ToDigitNumber, 9 | Sign, 10 | Num, 11 | MakeDigitNumber, 12 | InvertSign, 13 | Normalize, 14 | } from "./common"; 15 | import { CompareDigits } from "./compare"; 16 | import { SubDigits } from "./substraction-digits"; 17 | 18 | type AddDigitNumbers< 19 | T extends DigitNumber, 20 | U extends DigitNumber 21 | > = Sign extends Sign 22 | ? MakeDigitNumber, AddDigits, Num>> 23 | : CompareDigits, Num> extends 1 24 | ? MakeDigitNumber, SubDigits, Num>> 25 | : MakeDigitNumber, SubDigits, Num>>; 26 | 27 | export type Add< 28 | T extends number | bigint, 29 | U extends number | bigint 30 | > = ToNumber< 31 | FromDigitNumber< 32 | Normalize< 33 | AddDigitNumbers>, ToDigitNumber>> 34 | > 35 | > 36 | >; 37 | -------------------------------------------------------------------------------- /src/common.ts: -------------------------------------------------------------------------------- 1 | export type ToNumber = T extends `${infer N extends 2 | | number 3 | | bigint}` 4 | ? N 5 | : never; 6 | 7 | export type ToString = `${T}`; 8 | 9 | export type Digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 10 | export type Digit = Digits[number]; 11 | 12 | export type DigitNumber = { sign: "-" | ""; num: Digit[] }; 13 | export type MakeDigitNumber = { 14 | sign: S; 15 | num: N; 16 | }; 17 | 18 | export type ToDigits< 19 | T extends string, 20 | Acc extends Digit[] = [] 21 | > = T extends `${infer N extends Digit}${infer R}` 22 | ? ToDigits 23 | : Acc; 24 | 25 | export type ToDigitNumber = T extends `-${infer R}` 26 | ? { sign: "-"; num: ToDigits } 27 | : { sign: ""; num: ToDigits }; 28 | 29 | export type FromDigits = T extends [ 30 | infer N extends Digit, 31 | ...infer R 32 | ] 33 | ? FromDigits 34 | : Acc; 35 | 36 | export type Sign = T["sign"]; 37 | export type InvertSign = Sign extends "-" ? "" : "-"; 38 | export type MulSign = S1 extends "-" 39 | ? S2 extends "-" 40 | ? "" 41 | : "-" 42 | : S2 extends "-" 43 | ? "-" 44 | : ""; 45 | 46 | export type Num = T["num"]; 47 | 48 | export type FromDigitNumber = `${Sign}${FromDigits< 49 | Num 50 | >}`; 51 | 52 | export type TrimZeros = T extends [0] 53 | ? [0] 54 | : T extends [0, ...infer R extends Digit[]] 55 | ? TrimZeros 56 | : T; 57 | 58 | export type Normalize< 59 | T extends DigitNumber, 60 | Trim extends Digit[] = TrimZeros> 61 | > = Trim extends [0] 62 | ? MakeDigitNumber<"", Trim> 63 | : MakeDigitNumber, Trim>; 64 | -------------------------------------------------------------------------------- /src/compare.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ToString, 3 | Digit, 4 | DigitNumber, 5 | ToDigitNumber, 6 | Sign, 7 | Num, 8 | } from "./common"; 9 | 10 | export type CompareLength< 11 | T extends any[], 12 | U extends any[] 13 | > = T["length"] extends U["length"] ? 1 : 0; 14 | 15 | export type DigitCompareTable = [ 16 | [0, -1, -1, -1, -1, -1, -1, -1, -1, -1], 17 | [1, 0, -1, -1, -1, -1, -1, -1, -1, -1], 18 | [1, 1, 0, -1, -1, -1, -1, -1, -1, -1], 19 | [1, 1, 1, 0, -1, -1, -1, -1, -1, -1], 20 | [1, 1, 1, 1, 0, -1, -1, -1, -1, -1], 21 | [1, 1, 1, 1, 1, 0, -1, -1, -1, -1], 22 | [1, 1, 1, 1, 1, 1, 0, -1, -1, -1], 23 | [1, 1, 1, 1, 1, 1, 1, 0, -1, -1], 24 | [1, 1, 1, 1, 1, 1, 1, 1, 0, -1], 25 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 0] 26 | ]; 27 | 28 | export type DigitCompare< 29 | D1 extends Digit, 30 | D2 extends Digit 31 | > = DigitCompareTable[D1][D2]; 32 | 33 | export type CompareDigitsWithEqualLength< 34 | T extends Digit[], 35 | U extends Digit[] 36 | > = T extends [infer N1 extends Digit, ...infer R1 extends Digit[]] 37 | ? U extends [infer N2 extends Digit, ...infer R2 extends Digit[]] 38 | ? DigitCompare extends 0 39 | ? CompareDigitsWithEqualLength 40 | : DigitCompare 41 | : 0 42 | : 0; 43 | 44 | export type CompareDigits = CompareLength< 45 | T, 46 | U 47 | > extends 1 48 | ? CompareDigitsWithEqualLength 49 | : keyof U extends keyof T 50 | ? 1 51 | : -1; 52 | 53 | export type CompareDigitNumbers< 54 | T extends DigitNumber, 55 | U extends DigitNumber 56 | > = Sign extends Sign 57 | ? Sign extends "" 58 | ? CompareDigits, Num> 59 | : CompareDigits, Num> 60 | : Sign extends "-" 61 | ? -1 62 | : 1; 63 | 64 | /** 65 | * Compare two numbers 66 | * @param T - First number 67 | * @param U - Second number 68 | * @returns 0 if T = U, 1 if T > U, -1 if T < U 69 | */ 70 | export type Compare< 71 | T extends number | bigint, 72 | U extends number | bigint 73 | > = T extends U 74 | ? 0 75 | : CompareDigitNumbers>, ToDigitNumber>>; 76 | -------------------------------------------------------------------------------- /src/division-digits.ts: -------------------------------------------------------------------------------- 1 | import { Digit, Digits, TrimZeros } from "./common"; 2 | import { CompareDigits } from "./compare"; 3 | import { AddDigits } from "./addition-digits"; 4 | import { SubDigits } from "./substraction-digits"; 5 | 6 | export type Rest = T extends [ 7 | Digit, 8 | ...infer R extends Digit[] 9 | ] 10 | ? R 11 | : never; 12 | 13 | type TruncateWith< 14 | T extends Digit[], 15 | U extends Digit[], 16 | Acc extends Digit[] = [] 17 | > = U extends [] 18 | ? [T, Acc] 19 | : T extends [infer D extends Digit, ...infer DR extends Digit[]] 20 | ? TruncateWith, [...Acc, D]> 21 | : [T, Acc]; 22 | 23 | type DivModByDigit< 24 | D extends Digit[], 25 | M extends Digit[], 26 | Mul extends Digit[] = [0], 27 | IterTable extends Digit[] = Digits, 28 | NextMul extends Digit[] = AddDigits, 29 | Comp = CompareDigits 30 | > = IterTable extends [ 31 | infer Iteration extends Digit, 32 | ...infer Next extends Digit[] 33 | ] 34 | ? Comp extends 0 35 | ? { Quotient: Next[0]; Remainder: [0] } 36 | : Comp extends 1 37 | ? DivModByDigit 38 | : { 39 | Quotient: Iteration; 40 | Remainder: SubDigits; 41 | } 42 | : never; 43 | 44 | /** 45 | * compute the long division of a number by a divisor 46 | * @param A the Numerator Cut after M digits 47 | * @param D the Numerator Cut with M first digits 48 | * @param M the Divisor 49 | * @param Q the Quotient 50 | * @see https://en.wikipedia.org/wiki/Long_division#Algorithm_for_arbitrary_base 51 | */ 52 | export type DivModDigits< 53 | A extends Digit[], 54 | D extends Digit[], 55 | M extends Digit[], 56 | Q extends Digit[] = [] 57 | > = DivModByDigit extends { 58 | Quotient: infer B extends Digit; 59 | Remainder: infer R extends Digit[]; 60 | } 61 | ? A extends [infer A1 extends Digit, ...infer AR extends Digit[]] 62 | ? DivModDigits, M, [...Q, B]> 63 | : { Quotient: [...Q, B]; Remainder: R } 64 | : never; 65 | 66 | export type DivDigits = TruncateWith< 67 | N, 68 | M 69 | > extends [infer A extends Digit[], infer D extends Digit[]] 70 | ? DivModDigits["Quotient"] 71 | : never; 72 | 73 | export type ModDigits = TruncateWith< 74 | N, 75 | M 76 | > extends [infer A extends Digit[], infer D extends Digit[]] 77 | ? DivModDigits["Remainder"] 78 | : never; 79 | -------------------------------------------------------------------------------- /src/division.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ToNumber, 3 | MakeDigitNumber, 4 | FromDigitNumber, 5 | Normalize, 6 | DigitNumber, 7 | Sign, 8 | Num, 9 | ToDigitNumber, 10 | ToString, 11 | MulSign, 12 | } from "./common"; 13 | import { DivDigits, ModDigits } from "./division-digits"; 14 | 15 | export type DivDigitNumbers< 16 | T extends DigitNumber, 17 | U extends DigitNumber 18 | > = MakeDigitNumber, Sign>, DivDigits, Num>>; 19 | 20 | export type Div< 21 | T extends number | bigint, 22 | U extends number | bigint 23 | > = ToNumber< 24 | FromDigitNumber< 25 | Normalize< 26 | DivDigitNumbers>, ToDigitNumber>> 27 | > 28 | > 29 | >; 30 | 31 | export type ModDigitNumbers< 32 | T extends DigitNumber, 33 | U extends DigitNumber 34 | > = MakeDigitNumber, ModDigits, Num>>; 35 | 36 | export type Mod< 37 | T extends number | bigint, 38 | U extends number | bigint 39 | > = ToNumber< 40 | FromDigitNumber< 41 | Normalize< 42 | ModDigitNumbers>, ToDigitNumber>> 43 | > 44 | > 45 | >; 46 | -------------------------------------------------------------------------------- /src/factorial.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Digit, 3 | MakeDigitNumber, 4 | ToNumber, 5 | Normalize, 6 | FromDigitNumber, 7 | } from "./common"; 8 | import { MulDigits } from "./multiply-digits"; 9 | import { RangeOfDigits } from "./range"; 10 | 11 | type ProductOfTupleDigits< 12 | Range extends Digit[][], 13 | Acc extends Digit[] = [1] 14 | > = Range extends [infer N extends Digit[], ...infer R extends Digit[][]] 15 | ? ProductOfTupleDigits> 16 | : Acc; 17 | 18 | export type Factorial = ToNumber< 19 | FromDigitNumber< 20 | Normalize>>> 21 | > 22 | >; 23 | -------------------------------------------------------------------------------- /src/fizzbuzz-digits.ts: -------------------------------------------------------------------------------- 1 | import { Digit } from "./common"; 2 | import { ModDigits } from "./division-digits"; 3 | 4 | export type FizzBuzzDigits< 5 | N extends Digit[], 6 | Fizz extends Digit[] = ModDigits, 7 | Buzz extends Digit[] = ModDigits 8 | > = Fizz extends [0] 9 | ? Buzz extends [0] 10 | ? "FizzBuzz" 11 | : "Fizz" 12 | : Buzz extends [0] 13 | ? "Buzz" 14 | : N; 15 | -------------------------------------------------------------------------------- /src/fizzbuzz.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ToNumber, 3 | MakeDigitNumber, 4 | FromDigitNumber, 5 | Normalize, 6 | DigitNumber, 7 | Sign, 8 | Num, 9 | ToDigitNumber, 10 | ToString, 11 | MulSign, 12 | Digit, 13 | } from "./common"; 14 | import { FizzBuzzDigits } from "./fizzbuzz-digits"; 15 | 16 | export type FizzBuzzDigitNumbers< 17 | T extends DigitNumber, 18 | Result extends Digit[] | string = FizzBuzzDigits> 19 | > = Result extends Digit[] ? MakeDigitNumber, Result> : Result; 20 | 21 | export type FizzBuzz< 22 | T extends number | bigint, 23 | Result extends string | DigitNumber = FizzBuzzDigitNumbers< 24 | ToDigitNumber> 25 | > 26 | > = Result extends DigitNumber ? FromDigitNumber> : Result; 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./absolute"; 2 | export * from "./addition"; 3 | export * from "./compare"; 4 | export * from "./division"; 5 | export * from "./factorial"; 6 | export * from "./multiply"; 7 | export * from "./negate"; 8 | export * from "./power"; 9 | export * from "./range"; 10 | export * from "./substraction"; 11 | -------------------------------------------------------------------------------- /src/multiply-digits.ts: -------------------------------------------------------------------------------- 1 | import { Digit, TrimZeros } from "./common"; 2 | import { AddDigits } from "./addition-digits"; 3 | import { SubDigits } from "./substraction-digits"; 4 | 5 | export type MulX2 = AddDigits; 6 | export type MulX3 = AddDigits>; 7 | export type MulX4 = MulX2>; 8 | export type MulX5 = AddDigits>; 9 | export type MulX6 = MulX2>; 10 | export type MulX7 = SubDigits, MulX3>; 11 | export type MulX8 = SubDigits, MulX2>; 12 | export type MulX9 = SubDigits, T>; 13 | export type MulX10 = [...T, 0]; 14 | 15 | export type MulByDigit = U extends 0 16 | ? [0] 17 | : U extends 1 18 | ? T 19 | : U extends 2 20 | ? MulX2 21 | : U extends 3 22 | ? MulX3 23 | : U extends 4 24 | ? MulX4 25 | : U extends 5 26 | ? MulX5 27 | : U extends 6 28 | ? MulX6 29 | : U extends 7 30 | ? MulX7 31 | : U extends 8 32 | ? MulX8 33 | : MulX9; 34 | 35 | export type MulDigits< 36 | T extends Digit[], 37 | U extends Digit[], 38 | Acc extends Digit[] = [] 39 | > = U extends [infer N extends Digit, ...infer R extends Digit[]] 40 | ? MulDigits, MulX10>> 41 | : Acc; 42 | -------------------------------------------------------------------------------- /src/multiply.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ToNumber, 3 | MakeDigitNumber, 4 | FromDigitNumber, 5 | Normalize, 6 | DigitNumber, 7 | Sign, 8 | Num, 9 | ToDigitNumber, 10 | ToString, 11 | MulSign, 12 | } from "./common"; 13 | import { MulDigits } from "./multiply-digits"; 14 | 15 | export type MulDigitNumbers< 16 | T extends DigitNumber, 17 | U extends DigitNumber 18 | > = MakeDigitNumber, Sign>, MulDigits, Num>>; 19 | 20 | export type Mul< 21 | T extends number | bigint, 22 | U extends number | bigint 23 | > = ToNumber< 24 | FromDigitNumber< 25 | Normalize< 26 | MulDigitNumbers>, ToDigitNumber>> 27 | > 28 | > 29 | >; 30 | -------------------------------------------------------------------------------- /src/negate.ts: -------------------------------------------------------------------------------- 1 | export type Negate = 2 | `${T}` extends `-${infer U extends number | bigint}` 3 | ? U 4 | : `-${T}` extends `${infer U extends number | bigint}` 5 | ? U 6 | : never; 7 | -------------------------------------------------------------------------------- /src/power-digits.ts: -------------------------------------------------------------------------------- 1 | import { Digit, TrimZeros } from "./common"; 2 | import { DivModDigits } from "./division-digits"; 3 | import { MulDigits } from "./multiply-digits"; 4 | 5 | export type PowerDigits< 6 | T extends Digit[], 7 | U extends Digit[], 8 | Acc extends Digit[] = [1] 9 | > = U extends [0] 10 | ? [1] 11 | : U extends [1] 12 | ? MulDigits 13 | : U extends [infer UN extends Digit, ...infer UR extends Digit[]] 14 | ? DivModDigits extends { 15 | Quotient: infer Q extends Digit[]; 16 | Remainder: infer R extends Digit[]; 17 | } 18 | ? TrimZeros extends [0] 19 | ? PowerDigits, TrimZeros, Acc> 20 | : PowerDigits, TrimZeros, MulDigits> 21 | : never 22 | : Acc; 23 | -------------------------------------------------------------------------------- /src/power.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ToNumber, 3 | MakeDigitNumber, 4 | FromDigitNumber, 5 | Normalize, 6 | DigitNumber, 7 | Sign, 8 | Num, 9 | ToDigitNumber, 10 | ToString, 11 | Digit, 12 | } from "./common"; 13 | import { PowerDigits } from "./power-digits"; 14 | 15 | type PowerSign = S extends "-" 16 | ? Num extends [...Digit[], 0 | 2 | 4 | 6 | 8] 17 | ? "" 18 | : "-" 19 | : ""; 20 | 21 | export type PowerDigitNumbers< 22 | T extends DigitNumber, 23 | U extends DigitNumber 24 | > = Sign extends "-" 25 | ? MakeDigitNumber, [0]> 26 | : MakeDigitNumber, U>, PowerDigits, Num>>; 27 | 28 | export type Power< 29 | T extends number | bigint, 30 | U extends number | bigint 31 | > = ToNumber< 32 | FromDigitNumber< 33 | Normalize< 34 | PowerDigitNumbers>, ToDigitNumber>> 35 | > 36 | > 37 | >; 38 | -------------------------------------------------------------------------------- /src/range.ts: -------------------------------------------------------------------------------- 1 | import { Add } from "./addition"; 2 | import { AddDigits } from "./addition-digits"; 3 | import { Digit, Num, ToDigitNumber, ToString } from "./common"; 4 | import { Sub } from "./substraction"; 5 | 6 | export type SequenceOfDigits< 7 | T extends number | bigint, 8 | Min extends number | bigint = 0, 9 | MinDigits extends Digit[] = Num>>, 10 | Acc extends Digit[][] = [MinDigits] 11 | > = Acc["length"] extends T 12 | ? Acc 13 | : SequenceOfDigits< 14 | T, 15 | Min, 16 | MinDigits, 17 | [ 18 | ...Acc, 19 | AddDigits>>, MinDigits> 20 | ] 21 | >; 22 | 23 | export type RangeOfDigits< 24 | Min extends number | bigint, 25 | Max extends number | bigint 26 | > = SequenceOfDigits, Min>, Min>; 27 | -------------------------------------------------------------------------------- /src/substraction-digits.ts: -------------------------------------------------------------------------------- 1 | import type { Digit } from "./common"; 2 | 3 | type SubDigitTable = [ 4 | [ 5 | [0, 9, 8, 7, 6, 5, 4, 3, 2, 1], 6 | [1, 0, 9, 8, 7, 6, 5, 4, 3, 2], 7 | [2, 1, 0, 9, 8, 7, 6, 5, 4, 3], 8 | [3, 2, 1, 0, 9, 8, 7, 6, 5, 4], 9 | [4, 3, 2, 1, 0, 9, 8, 7, 6, 5], 10 | [5, 4, 3, 2, 1, 0, 9, 8, 7, 6], 11 | [6, 5, 4, 3, 2, 1, 0, 9, 8, 7], 12 | [7, 6, 5, 4, 3, 2, 1, 0, 9, 8], 13 | [8, 7, 6, 5, 4, 3, 2, 1, 0, 9], 14 | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 15 | ], 16 | [ 17 | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 18 | [0, 9, 8, 7, 6, 5, 4, 3, 2, 1], 19 | [1, 0, 9, 8, 7, 6, 5, 4, 3, 2], 20 | [2, 1, 0, 9, 8, 7, 6, 5, 4, 3], 21 | [3, 2, 1, 0, 9, 8, 7, 6, 5, 4], 22 | [4, 3, 2, 1, 0, 9, 8, 7, 6, 5], 23 | [5, 4, 3, 2, 1, 0, 9, 8, 7, 6], 24 | [6, 5, 4, 3, 2, 1, 0, 9, 8, 7], 25 | [7, 6, 5, 4, 3, 2, 1, 0, 9, 8], 26 | [8, 7, 6, 5, 4, 3, 2, 1, 0, 9] 27 | ] 28 | ]; 29 | 30 | type SubDigitCarryTable = [ 31 | [ 32 | [0, 1, 1, 1, 1, 1, 1, 1, 1, 1], 33 | [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 34 | [0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 35 | [0, 0, 0, 0, 1, 1, 1, 1, 1, 1], 36 | [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], 37 | [0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 38 | [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 39 | [0, 0, 0, 0, 0, 0, 0, 0, 1, 1], 40 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 41 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 42 | ], 43 | [ 44 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 45 | [0, 1, 1, 1, 1, 1, 1, 1, 1, 1], 46 | [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 47 | [0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 48 | [0, 0, 0, 0, 1, 1, 1, 1, 1, 1], 49 | [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], 50 | [0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 51 | [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 52 | [0, 0, 0, 0, 0, 0, 0, 0, 1, 1], 53 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] 54 | ] 55 | ]; 56 | 57 | type SubDigit< 58 | T extends Digit, 59 | U extends Digit, 60 | Carry extends 0 | 1 = 0 61 | > = SubDigitTable[Carry][T][U]; 62 | 63 | type SubCarryDigit< 64 | T extends Digit, 65 | U extends Digit, 66 | Carry extends 0 | 1 = 0 67 | > = SubDigitCarryTable[Carry][T][U]; 68 | 69 | export type SubDigits< 70 | T extends Digit[], 71 | U extends Digit[], 72 | Carry extends 0 | 1 = 0, 73 | Acc extends Digit[] = [] 74 | > = T extends [...infer R extends Digit[], infer N extends Digit] 75 | ? U extends [...infer S extends Digit[], infer M extends Digit] 76 | ? SubDigits< 77 | R, 78 | S, 79 | SubCarryDigit, 80 | [SubDigit, ...Acc] 81 | > 82 | : SubDigits< 83 | R, 84 | [], 85 | SubCarryDigit, 86 | [SubDigit, ...Acc] 87 | > 88 | : U extends [...infer S extends Digit[], infer M extends Digit] 89 | ? SubDigits< 90 | [], 91 | S, 92 | SubCarryDigit<0, M, Carry>, 93 | [SubDigit<0, M, Carry>, ...Acc] 94 | > 95 | : Carry extends 1 96 | ? [...Acc, 9] 97 | : Acc; 98 | -------------------------------------------------------------------------------- /src/substraction.ts: -------------------------------------------------------------------------------- 1 | import { AddDigits } from "./addition-digits"; 2 | import { 3 | DigitNumber, 4 | FromDigitNumber, 5 | InvertSign, 6 | MakeDigitNumber, 7 | Normalize, 8 | Num, 9 | Sign, 10 | ToDigitNumber, 11 | ToNumber, 12 | ToString, 13 | } from "./common"; 14 | import { CompareDigits } from "./compare"; 15 | import { SubDigits } from "./substraction-digits"; 16 | 17 | type SubDigitNumbers< 18 | T extends DigitNumber, 19 | U extends DigitNumber 20 | > = Sign extends Sign 21 | ? CompareDigits, Num> extends 1 22 | ? MakeDigitNumber, SubDigits, Num>> 23 | : MakeDigitNumber, SubDigits, Num>> 24 | : MakeDigitNumber, AddDigits, Num>>; 25 | 26 | export type Sub< 27 | T extends number | bigint, 28 | U extends number | bigint 29 | > = ToNumber< 30 | FromDigitNumber< 31 | Normalize< 32 | SubDigitNumbers>, ToDigitNumber>> 33 | > 34 | > 35 | >; 36 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | import { FizzBuzz } from "./fizzbuzz"; 2 | import { Add, Sub, Mul, Div, Mod, Power, Factorial } from "./index"; 3 | 4 | type TestAdd = Add<1234567890976509876543456n, 234567876542n>; 5 | // ^? 6 | 7 | type TestSub = Sub<1234567890976509876543456n, 234567876542n>; 8 | // ^? 9 | 10 | type TestMul = Mul<1234567890976509876543456n, 234567876542n>; 11 | // ^? 12 | 13 | type TestDiv = Div<1234567890976509876543456n, 234567876542n>; 14 | // ^? 15 | 16 | type TestMod = Mod<1234567890976509876543456n, 234567876542n>; 17 | // ^? 18 | 19 | type TestEuclidianEquality = Add, TestMod>; 20 | // ^? 21 | 22 | type TestPower = Power<-17, 42>; 23 | // ^? 24 | 25 | type TestFactorial = Factorial<42>; 26 | // ^? 27 | 28 | type TestFizzBuzz = FizzBuzz<1234567890976509876543450n>; 29 | // ^? 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // ts config for es 2021 3 | "compilerOptions": { 4 | "target": "ES2019", 5 | "module": "CommonJS", 6 | "moduleResolution": "Node", 7 | "lib": ["ES2019"], 8 | "outDir": "./lib", 9 | "alwaysStrict": true, 10 | "strict": true, 11 | "esModuleInterop": true, 12 | "sourceMap": true, 13 | "declaration": true, 14 | "jsx": "react-jsx" 15 | }, 16 | "exclude": ["node_modules", "lib"] 17 | } 18 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | typescript@^4.8.2: 6 | version "4.8.2" 7 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" 8 | integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== 9 | --------------------------------------------------------------------------------