type-plus
Version:
Provides additional types for TypeScript.
657 lines (619 loc) • 22.2 kB
text/typescript
import type { Tail } from '../tuple/tail.js'
import type { PadStart } from '../tuple/tuple_plus.pad_start.js'
import type { Add as NumericAdd } from './add.js'
import type { ToNegative } from './math_plus.to_negative.js'
/**
* Internal numeric representation to perform math operations.
*
* NumericStruct: `[Type, DigitsStruct]`
* DigitsStruct: `[Sign, Digits, Exponent]`
*
* It is similar to the floating point representation with some minor differences.
*
* @template Type Type of the value, either `number` or `bigint`.
* It captures the original type of the value,
* so that at the end of the operation,
* the value can be adjusted accordingly.
*
* @template Sign Sign of the value, either `+` or `-`.
*
* @template Digits Digits of the value.
* It is a tuple of digits,
* where each digits can range from 0 to 9 during input,
* and range from -10 to 89 during operation.
* The max 89 comes from multiplication:
*
* ```
* 99 * 9
* => [[ 9, 9], 0]
* * [ [9], 0]
* => [[ 81, 81], 0]
* => [[ 89, 1], 0]
* => [[ 8, 9, 1], 0]
* ```
*
* While -10 comes from subtraction:
*
* ```
* 100 - 99 = 1
* => [[ 1, 0, 0], 0]
* - [[ 9, 9], 0]
* => [[ 1, -9, -9], 0]
* => [[ 1,-10, 1], 0] // here, as in intermediate step
* => [[ 0, 0, 1], 0]
* => [[1], 0]
* => 1
* ```
*
*
* Unlike floating point numbers, the digits length is not limited.
*
* @template Exponent Exponent is the negative exponent of the number.
*
* ```
* 1.23 = 123e^-2 = [[1, 2, 3], 2]
* 0.0123 = 123e^-4 = [[1, 2, 3], 4]
* ```
*
* There are 2 kinds of `NumericStruct`:
* - Normalized: The `NumericStruct` is clean and can be converted to/from `number` or `bigint`
* - Not normalized: The `DigitsStruct` within the `NumericStruct` is normalized,
* but may need to convert between `number` and `bigint`.\
* e.g. bigint + float => float (if possible), number + number => bigint (too big)
*
* During operations, the `DigitsStruct` can be not normalized,
* but each operation should always normalize the `DigitsStruct` before returning.
* Each operations assume the input `DigitsStruct` is normalized.
*
* All operations are performed in similar way:
*
* value -> NormalizedNumericStruct -> operation(NormalizedDigitsStruct) -> NormalizedNumericStruct -> Value
*
* This allows the operations to be composable.
* */
export type NumericStruct = ['bigint' | 'number', DigitsStruct]
// These are used to reference the NumericStruct values
export type TYPE = 0
export type DIGITS_STRUCT = 1
export namespace NumericStruct {
/**
* Creates a `NumericStruct` from number or bigint `N`.
*/
export type FromNumeric<N extends number | bigint, Fail = never> = N extends number
? number extends N
? Fail
: ['number', DigitsStruct.FromNumber<N>]
: N extends bigint
? bigint extends N
? Fail
: ['bigint', DigitsStruct.FromBigint<N>]
: never
/**
* Converts a `NumericStruct` to a number or bigint.
*
* It includes the normalization of the `NumericStruct`.
*/
export type ToNumeric<M extends NumericStruct> = DigitsStruct.ToString<
M[DIGITS_STRUCT]
> extends infer S extends string
? M[TYPE] extends 'bigint'
? StringToBigint<S, StringToNumber<S, `The value '${S}' cannot be represented as bigint or number`>>
: StringToNumber<S, StringToBigint<S, `The value '${S}' cannot be represented as bigint or number`>>
: never
export type Add<A extends NumericStruct, B extends NumericStruct> = [
A[TYPE],
DigitsStruct.Add<A[DIGITS_STRUCT], B[DIGITS_STRUCT]>
]
export type Subtract<A extends NumericStruct, B extends NumericStruct> = [
A[TYPE],
DigitsStruct.Subtract<A[DIGITS_STRUCT], B[DIGITS_STRUCT]>
]
export type Multiply<A extends NumericStruct, B extends NumericStruct> = [
A[TYPE],
DigitsStruct.Multiply<A[DIGITS_STRUCT], B[DIGITS_STRUCT]>
]
}
// TODO: move into `NumericHelpers`
type StringToBigint<S extends string, Fail> = S extends `${infer N extends bigint}` ? N : Fail
// TODO: move into `NumericHelpers`
export type StringToNumber<S extends string, Fail> = S extends `${infer N extends number}`
? number extends N
? Fail
: N
: Fail
export type DigitsStruct = [Sign: '+' | '-', Digits: number[], Exponent: number]
// These are used to reference the DigitsStruct values
export type SIGN = 0
export type DIGITS = 1
export type EXPONENT = 2
export namespace DigitsStruct {
/**
* Creates a `DigitsStruct` from number `N`.
*
* @template N Number to create `DigitsStruct` from.
*/
export type FromNumber<N extends number> = `${N}` extends `-${infer R}`
? R extends `${infer W}.${infer F}`
? [DigitArray.FromString<W>, DigitArray.FromString<F>] extends [
infer WA extends number[],
infer FA extends number[]
]
? ['-', DigitArray.TrimLeadingZeros<[...WA, ...FA]>, FA['length']]
: never
: ['-', DigitArray.FromString<R>, 0]
: `${N}` extends `${infer W}.${infer F}`
? [DigitArray.FromString<W>, DigitArray.FromString<F>] extends [
infer WA extends number[],
infer FA extends number[]
]
? ['+', DigitArray.TrimLeadingZeros<[...WA, ...FA]>, FA['length']]
: never
: ['+', DigitArray.FromString<`${N}`>, 0]
/**
* Creates a `DigitsStruct` from bigint `N`.
*
* @template N Number to create `DigitsStruct` from.
*/
export type FromBigint<N extends bigint> = `${N}` extends `-${infer R}`
? ['-', DigitArray.FromString<R>, 0]
: ['+', DigitArray.FromString<`${N}`>, 0]
/**
* Converts a `DigitsStruct` to string.
*
* @template D A normalized `DigitsStruct`.
*/
export type ToString<D extends DigitsStruct> = (
PadStart<D[DIGITS], D[EXPONENT], 0> extends infer Padded extends number[]
? Padded['length'] extends D[EXPONENT]
? DigitArray.ToString<[0, '.', ...DigitArray.TrimTrailingZeros<Padded>]>
: SplitFloat<Padded, D[EXPONENT]> extends [infer W extends number[], infer F extends number[]]
? F extends []
? DigitArray.ToString<W>
: DigitArray.ToString<[...W, '.', ...DigitArray.TrimTrailingZeros<F>]>
: never
: never
) extends infer R
? R extends '0'
? R
: R extends string
? D[SIGN] extends '-'
? `-${R}`
: R
: never
: never
/**
* Splits DigitArray into the whole number and the fractional part.
*
* @note cannot use `ArrayPlus.SplitAt` as it causes infinite loop.
*/
type SplitFloat<A extends number[], I extends number, F extends number[] = []> = I extends 0
? [A, []]
: F['length'] extends I
? [A, F]
: A extends [...infer H extends number[], infer T extends number]
? SplitFloat<H, I, [T, ...F]>
: never
/**
* Normalizes a `DigitsStruct`.
*
* The normalization two two things:
*
* - if the first digit is negative, it will flip the sign.
* - carry digits if the digit is negative or greater than 9.
*/
export type Normalize<
N extends DigitsStruct,
R extends DigitsStruct = ['+', [], 0]
> = `${N[DIGITS][0]}` extends `-${number}`
? Normalize<FlipSign<N>, R>
: [N[SIGN], DigitArray.CarryDigits<N[DIGITS]>, N[EXPONENT]]
type FlipSign<
D extends DigitsStruct,
I extends number[] = D[DIGITS],
R extends number[] = []
> = I extends []
? D[SIGN] extends '-'
? ['+', R, D[EXPONENT]]
: ['-', R, D[EXPONENT]]
: I extends [infer H extends number, ...infer T extends number[]]
? FlipSign<D, T, [...R, Digit.FlipSign<H>]>
: never
/**
* Add `A` and `B`.
*
* @template A A normalized `DigitsStruct`.
* @template B B normalized `DigitsStruct`.
*/
export type Add<A extends DigitsStruct, B extends DigitsStruct> = Balance<A, B> extends [
infer BA extends DigitsStruct,
infer BB extends DigitsStruct
]
? [BA[SIGN], BB[SIGN]] extends ['+', '+']
? Normalize<['+', DigitArray.Add<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['+', '-']
? Normalize<['+', DigitArray.Subtract<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['-', '+']
? Normalize<['+', DigitArray.Subtract<BB[DIGITS], BA[DIGITS]>, BB[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['-', '-']
? Normalize<['-', DigitArray.Add<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: never
: never
export type Subtract<A extends DigitsStruct, B extends DigitsStruct> = Balance<A, B> extends [
infer BA extends DigitsStruct,
infer BB extends DigitsStruct
]
? [BA[SIGN], BB[SIGN]] extends ['+', '+']
? Normalize<['+', DigitArray.Subtract<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['+', '-']
? Normalize<['+', DigitArray.Add<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['-', '+']
? Normalize<['-', DigitArray.Add<BB[DIGITS], BA[DIGITS]>, BA[EXPONENT]]>
: [BA[SIGN], BB[SIGN]] extends ['-', '-']
? Normalize<['-', DigitArray.Subtract<BA[DIGITS], BB[DIGITS]>, BA[EXPONENT]]>
: never
: never
export type Multiply<A extends DigitsStruct, B extends DigitsStruct> = NumericAdd<
A[EXPONENT],
B[EXPONENT]
> extends infer Exp extends number
? [A[SIGN], B[SIGN]] extends ['+', '+']
? Normalize<['+', DigitArray.Multiply<A[DIGITS], B[DIGITS]>, Exp]>
: [A[SIGN], B[SIGN]] extends ['+', '-']
? Normalize<['-', DigitArray.Multiply<A[DIGITS], B[DIGITS]>, Exp]>
: [A[SIGN], B[SIGN]] extends ['-', '+']
? Normalize<['-', DigitArray.Multiply<B[DIGITS], A[DIGITS]>, Exp]>
: [A[SIGN], B[SIGN]] extends ['-', '-']
? Normalize<['+', DigitArray.Multiply<A[DIGITS], B[DIGITS]>, Exp]>
: never
: never
/**
* Balance the two structs for add/subtract.
*/
export type Balance<A extends DigitsStruct, B extends DigitsStruct> = GetBalancePadding<
A[EXPONENT],
B[EXPONENT]
> extends [infer Pads extends number[], infer Longer]
? Longer extends 'A'
? [A, [B[SIGN], DigitArray.TrimLeadingZeros<[...B[DIGITS], ...Pads]>, A[EXPONENT]]]
: [[A[SIGN], DigitArray.TrimLeadingZeros<[...A[DIGITS], ...Pads]>, B[EXPONENT]], B]
: never
type GetBalancePadding<
A extends number,
B extends number,
C extends number[] = [],
R extends number[] = []
> = A extends B
? [[], 'A']
: R extends []
? // have not reach min yet
C['length'] extends A
? GetBalancePadding<A, B, [0, ...C], [0]>
: C['length'] extends B
? GetBalancePadding<A, B, [0, ...C], [0, ...R]>
: GetBalancePadding<A, B, [0, ...C], []>
: C['length'] extends A
? [R, 'A']
: C['length'] extends B
? [R, 'B']
: GetBalancePadding<A, B, [0, ...C], [0, ...R]>
/**
* This is used to align the `NumberStruct` during `Add/Subtract`.
*/
export type GetMinPadEnd<
A extends number,
B extends number,
R extends number[] = []
> = R['length'] extends A ? [R, 'B'] : R['length'] extends B ? [R, 'A'] : GetMinPadEnd<A, B, [0, ...R]>
}
export namespace DigitArray {
export type FromString<S extends string> = S extends `1${infer L}`
? [1, ...FromString<L>]
: S extends `2${infer L}`
? [2, ...FromString<L>]
: S extends `3${infer L}`
? [3, ...FromString<L>]
: S extends `4${infer L}`
? [4, ...FromString<L>]
: S extends `5${infer L}`
? [5, ...FromString<L>]
: S extends `6${infer L}`
? [6, ...FromString<L>]
: S extends `7${infer L}`
? [7, ...FromString<L>]
: S extends `8${infer L}`
? [8, ...FromString<L>]
: S extends `9${infer L}`
? [9, ...FromString<L>]
: S extends `0${infer L}`
? [0, ...FromString<L>]
: S extends `-1${infer L}`
? [-1, ...FromString<L>]
: S extends `-2${infer L}`
? [-2, ...FromString<L>]
: S extends `-3${infer L}`
? [-3, ...FromString<L>]
: S extends `-4${infer L}`
? [-4, ...FromString<L>]
: S extends `-5${infer L}`
? [-5, ...FromString<L>]
: S extends `-6${infer L}`
? [-6, ...FromString<L>]
: S extends `-7${infer L}`
? [-7, ...FromString<L>]
: S extends `-8${infer L}`
? [-8, ...FromString<L>]
: S extends `-9${infer L}`
? [-9, ...FromString<L>]
: S extends `-0${infer L}`
? [-0, ...FromString<L>]
: []
export type ToString<A extends Array<number | string>> = number extends A['length']
? ''
: A['length'] extends 0
? ''
: `${A[0]}${ToString<Tail<A>>}`
/**
* [0, 0, -1] => [-1]
*
* This is used in various places so that there will be less computation,
* and the sign bit can be handled properly.
*/
export type TrimLeadingZeros<T extends number[]> = T extends [0]
? T
: T extends [0, ...infer Tail extends number[]]
? TrimLeadingZeros<Tail>
: T
export type TrimTrailingZeros<T extends number[]> = T extends [0]
? T
: T extends [...infer Tail extends number[], 0]
? TrimTrailingZeros<Tail>
: T
export type Add<A extends number[], B extends number[], R extends number[] = []> = A extends []
? B extends []
? R
: B extends [...infer BH extends number[], infer BL extends number]
? Add<[], BH, [BL, ...R]>
: never
: B extends []
? A extends [...infer AH extends number[], infer AL extends number]
? Add<AH, [], [AL, ...R]>
: never
: [A, B] extends [
[...infer AH extends number[], infer AL extends number],
[...infer BH extends number[], infer BL extends number]
]
? Add<AH, BH, [Digit.Add<AL, BL>, ...R]>
: never
export type Subtract<A extends number[], B extends number[], R extends number[] = []> = A extends []
? B extends []
? TrimLeadingZeros<R>
: B extends [...infer BH extends number[], infer BL extends number]
? Subtract<[], BH, [ToNegative<BL>, ...R]>
: never
: B extends []
? A extends [...infer AH extends number[], infer AL extends number]
? Subtract<AH, [], [AL, ...R]>
: never
: [A, B] extends [
[...infer AH extends number[], infer AL extends number],
[...infer BH extends number[], infer BL extends number]
]
? Subtract<AH, BH, [Digit.Subtract<AL, BL>, ...R]>
: never
export type Multiply<A extends number[], B extends number[], R extends number[][] = []> = B extends []
? RecursiveAdd<R>
: B extends [infer Head extends number, ...infer Tail extends number[]]
? Multiply<A, Tail, [...R, CarryDigits<MultiplyArray<A, Head, Zeros<Tail['length']>>>]>
: never
type Zeros<N extends number, R extends number[] = []> = N extends unknown ? R['length'] extends N ? R : Zeros<N, [0, ...R]> : never
type MultiplyArray<
A extends number[],
B extends number,
Pad extends number[],
R extends number[] = []
> = B extends 0
? [0]
: B extends 1
? [...A, ...Pad]
: A extends []
? [...R, ...Pad]
: A extends [infer H extends number, ...infer T extends number[]]
? MultiplyArray<T, B, Pad, [...R, Digit.Multiply<H, B>]>
: never
/**
* Recursively add digit arrays.
*
* This is used in multiplication.
*/
type RecursiveAdd<E extends number[][], R extends number[] = []> = E extends []
? R
: E extends [infer H extends number[], ...infer T extends number[][]]
? RecursiveAdd<T, CarryDigits<Add<R, H>>>
: never
export type CarryDigits<N extends number[], R extends number[] = []> = N extends []
? TrimLeadingZeros<R>
: N extends [infer Tail extends number]
? `${Tail}` extends `${infer T1 extends number}${infer T2 extends number}`
? CarryDigits<[], [T1, T2, ...R]>
: `${Tail}` extends `-${infer T1 extends number}${infer T2 extends number}`
? `-${T1}` extends `${infer NT extends number}`
? CarryDigits<[], [NT, T2, ...R]>
: never
: CarryDigits<[], [Tail, ...R]>
: N extends [infer Head extends number, infer Tail extends number]
? `${Tail}` extends `${infer T1 extends number}${infer T2 extends number}`
? CarryDigits<[Digit.Add<Head, T1>], [T2, ...R]>
: `${Tail}` extends `-${infer T1 extends number}${infer T2 extends number}`
? `-${T1}` extends `${infer NT extends number}`
? CarryDigits<[Digit.Add<Head, NT>], [T2, ...R]>
: never
: `${Tail}` extends `-${number}`
? CarryDigits<[Digit.Add<Head, -1>], [Digit.Plus10[Tail], ...R]>
: CarryDigits<[Head], [Tail, ...R]>
: N extends [...infer Heads extends number[], infer Head extends number, infer Tail extends number]
? `${Tail}` extends `${infer T1 extends number}${infer T2 extends number}`
? CarryDigits<[...Heads, Digit.Add<Head, T1>], [T2, ...R]>
: `${Tail}` extends `-${infer T1 extends number}${infer T2 extends number}`
? `-${T1}` extends `${infer NT extends number}`
? CarryDigits<[...Heads, Digit.Add<Head, NT>], [T2, ...R]>
: never
: `${Tail}` extends `-${number}`
? CarryDigits<[...Heads, Digit.Add<Head, -1>], [Digit.Plus10[Tail], ...R]>
: CarryDigits<[...Heads, Head], [Tail, ...R]>
: never
}
export namespace Digit {
/**
* Adds two `Digit`.
*
* add: A: 0 - 9, B: 0 - 9
* normalize: [81, 81] -> [81 + 8, 1]
*/
export type Add<A extends number, B extends number> = `${A}` extends `-${infer AD extends number}`
? `${B}` extends `-${infer BD extends number}`
? ToNegative<PositiveEntryAdd<AD, BD>>
: Subtract<B, AD>
: `${B}` extends `-${infer BD extends number}`
? Subtract<A, BD>
: PositiveEntryAdd<A, B>
export type FlipSign<T extends number> = T extends 0
? 0
: `${T}` extends `-${infer R extends number}`
? R
: `-${T}` extends `${infer R extends number}`
? R
: never
type PositiveEntryAdd<A extends number, B extends number> = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
[6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
[9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21],
[13, 14, 15, 16, 17, 18, 19, 20, 21, 22],
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
[15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
[16, 17, 18, 19, 20, 21, 22, 23, 24, 25],
[17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
[18, 19, 20, 21, 22, 23, 24, 25, 26, 27],
[19, 20, 21, 22, 23, 24, 25, 26, 27, 28],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
[22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
[23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
[24, 25, 26, 27, 28, 29, 30, 31, 32, 33],
[25, 26, 27, 28, 29, 30, 31, 32, 33, 34],
[26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
[27, 28, 29, 30, 31, 32, 33, 34, 35, 36],
[28, 29, 30, 31, 32, 33, 34, 35, 36, 37],
[29, 30, 31, 32, 33, 34, 35, 36, 37, 38],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
[32, 33, 34, 35, 36, 37, 38, 39, 40, 41],
[33, 34, 35, 36, 37, 38, 39, 40, 41, 42],
[34, 35, 36, 37, 38, 39, 40, 41, 42, 43],
[35, 36, 37, 38, 39, 40, 41, 42, 43, 44],
[36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
[37, 38, 39, 40, 41, 42, 43, 44, 45, 46],
[38, 39, 40, 41, 42, 43, 44, 45, 46, 47],
[39, 40, 41, 42, 43, 44, 45, 46, 47, 48],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
[42, 43, 44, 45, 46, 47, 48, 49, 50, 51],
[43, 44, 45, 46, 47, 48, 49, 50, 51, 52],
[44, 45, 46, 47, 48, 49, 50, 51, 52, 53],
[45, 46, 47, 48, 49, 50, 51, 52, 53, 54],
[46, 47, 48, 49, 50, 51, 52, 53, 54, 55],
[47, 48, 49, 50, 51, 52, 53, 54, 55, 56],
[48, 49, 50, 51, 52, 53, 54, 55, 56, 57],
[49, 50, 51, 52, 53, 54, 55, 56, 57, 58],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60],
[52, 53, 54, 55, 56, 57, 58, 59, 60, 61],
[53, 54, 55, 56, 57, 58, 59, 60, 61, 62],
[54, 55, 56, 57, 58, 59, 60, 61, 62, 63],
[55, 56, 57, 58, 59, 60, 61, 62, 63, 64],
[56, 57, 58, 59, 60, 61, 62, 63, 64, 65],
[57, 58, 59, 60, 61, 62, 63, 64, 65, 66],
[58, 59, 60, 61, 62, 63, 64, 65, 66, 67],
[59, 60, 61, 62, 63, 64, 65, 66, 67, 68],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[61, 62, 63, 64, 65, 66, 67, 68, 69, 70],
[62, 63, 64, 65, 66, 67, 68, 69, 70, 71],
[63, 64, 65, 66, 67, 68, 69, 70, 71, 72],
[64, 65, 66, 67, 68, 69, 70, 71, 72, 73],
[65, 66, 67, 68, 69, 70, 71, 72, 73, 74],
[66, 67, 68, 69, 70, 71, 72, 73, 74, 75],
[67, 68, 69, 70, 71, 72, 73, 74, 75, 76],
[68, 69, 70, 71, 72, 73, 74, 75, 76, 77],
[69, 70, 71, 72, 73, 74, 75, 76, 77, 78],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80],
[72, 73, 74, 75, 76, 77, 78, 79, 80, 81],
[73, 74, 75, 76, 77, 78, 79, 80, 81, 82],
[74, 75, 76, 77, 78, 79, 80, 81, 82, 83],
[75, 76, 77, 78, 79, 80, 81, 82, 83, 84],
[76, 77, 78, 79, 80, 81, 82, 83, 84, 85],
[77, 78, 79, 80, 81, 82, 83, 84, 85, 86],
[78, 79, 80, 81, 82, 83, 84, 85, 86, 87],
[79, 80, 81, 82, 83, 84, 85, 86, 87, 88],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
][A][B]
/**
* Subtract two positive numbers.
* The number range from 0 to 81.
*/
export type Subtract<A extends number, B extends number> = [`${A}`, `${B}`] extends [
`${number}${infer A2 extends number}`,
`${number}${infer B2 extends number}`
]
? Subtract<A2, B2>
: `${A}` extends `${number}${infer A2 extends number}`
? Subtract<A2, B>
: `${B}` extends `${number}${infer B2 extends number}`
? Subtract<A, B2>
: SingleDigitSubtract<A, B>
export type SingleDigitSubtract<A extends number, B extends number> = [
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9],
[1, 0, -1, -2, -3, -4, -5, -6, -7, -8],
[2, 1, 0, -1, -2, -3, -4, -5, -6, -7],
[3, 2, 1, 0, -1, -2, -3, -4, -5, -6],
[4, 3, 2, 1, 0, -1, -2, -3, -4, -5],
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4],
[6, 5, 4, 3, 2, 1, 0, -1, -2, -3],
[7, 6, 5, 4, 3, 2, 1, 0, -1, -2],
[8, 7, 6, 5, 4, 3, 2, 1, 0, -1],
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
][A][B]
export type Plus10 = { [k in number]: number } & {
'-1': 9,
'-2': 8,
'-3': 7,
'-4': 6,
'-5': 5,
'-6': 4,
'-7': 3,
'-8': 2,
'-9': 1
}
export type Multiply<A extends number, B extends number> = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18],
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27],
[0, 4, 8, 12, 16, 20, 24, 28, 32, 36],
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45],
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54],
[0, 7, 14, 21, 28, 35, 42, 49, 56, 63],
[0, 8, 16, 24, 32, 40, 48, 56, 64, 72],
[0, 9, 18, 27, 36, 45, 54, 63, 72, 81]
][A][B]
}