ts-arithmetic
Version:
Type Level Arithmetic
656 lines (491 loc) • 36.5 kB
TypeScript
/**
* Get the absolute value of a numeric literal
*
* @param N - The number to get the absolute value of.
* @returns N as a positive number.
*
* @public
*/
export declare type Abs<N extends number> = (N extends N ? `${N}` extends `-${infer M extends number}` ? M : N : never);
/**
* Add two numeric type literals.
*
* @param X - The first operand.
* @param Y - The second operand.
* @returns X + Y
*
* @public
*/
export declare type Add<X extends number, Y extends number> = (SomeElementExtends<[X, Y], never> extends 1 ? never : X extends 0 ? Y : Y extends 0 ? X : number extends (X | Y) ? number : AddNumbers<X, Y>);
declare type AdditionTable = MakeAdditionTable<[FirstAdditiveResultRow]>;
declare type AdditiveOperationResult<C extends Bit = Bit, R extends Digit = Digit> = OperationResult<C, R>;
declare type AdditiveOperationTable = AdditiveOperationResult[][];
/**
* Add two numeric type literals
*
* @internal
*/
declare type AddNumbers<X extends number, Y extends number> = SignedFloatToNum<AddSignedFloats<ToSignedFloat<X>, ToSignedFloat<Y>>>;
declare type AddSignedFloats<X extends SignedFloat, Y extends SignedFloat> = (X extends SignedFloat<infer XSign, infer XUnsignedFloat> ? Y extends SignedFloat<infer YSign, infer YUnsignedFloat> ? {
'-': {
'-': SignedFloat<'-', AddUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
'+': NegateSignedFloat<SubtractUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
};
'+': {
'-': SubtractUnsignedFloats<XUnsignedFloat, YUnsignedFloat>;
'+': SignedFloat<'+', AddUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
};
}[XSign][YSign] : never : never);
declare type AddUnsignedFloats<X extends UnsignedFloat, Y extends UnsignedFloat> = (Normalise<X, Y> extends [...DigitsPair<infer TNormalisedX, infer TNormalisedY>, infer TDecimalPlaces extends number] ? DigitsToUnsignedFloat<DigitwiseAdd<TNormalisedX, TNormalisedY>, TDecimalPlaces> : never);
declare type AddUnsignedInts<X extends Digit[], Y extends Digit[]> = (NormaliseIntPartLengths<X, Y> extends DigitsPair<infer TNormalisedX, infer TNormalisedY> ? DigitwiseAdd<TNormalisedX, TNormalisedY> : never);
/**
* Perform an AND operation on two Bit literals.
*
* @param A - The first operand.
* @param B - The second operand.
* @returns Bit - (A & B)
*
* @public
*/
export declare type And<A extends Bit, B extends Bit> = AndMap[A][B];
declare type AndMap = TwoBitMap<[0, 0, 0, 1]>;
declare type ArrayOf<TLength extends number, TValue, A extends TValue[] = []> = (A['length'] extends TLength ? A : ArrayOf<TLength, TValue, [TValue, ...A]>);
/**
* Used to represent true or false, but can be used to key into objects/tuples.
*
* @public
*/
export declare type Bit = 0 | 1;
declare type BitMap<TFalse = unknown, TTrue = unknown> = {
0: TFalse;
1: TTrue;
};
/**
* Compare two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns (-1 | 0 | 1) - (-1 if X is less than Y, 1 if X is greater than Y, 0 if X === Y).
*
* @public
*/
export declare type Compare<X extends number, Y extends number> = (SomeElementExtends<[X, Y], never> extends 1 ? never : number extends (X | Y) ? ComparisonResult : X extends X ? Y extends Y ? _Compare<X, Y> : never : never);
declare type _Compare<X extends number, Y extends number> = (SignDecisionBranch<X, Y, {
'-': {
'-': CompareNumberMagnitudes<Y, X>;
'+': -1;
};
'+': {
'-': 1;
'+': CompareNumberMagnitudes<X, Y>;
};
}>);
declare type CompareDecisionBranch<X extends number, Y extends number, TMap extends _CompareMap> = TMap[Compare<X, Y>];
declare type CompareDigits<A extends Digit, B extends Digit> = (A extends B ? 0 : _CompareDigits<A, B>);
declare type _CompareDigits<A extends Digit, B extends Digit, TOrderedDigits extends Digit[] = OrderedDigits> = (TOrderedDigits extends HeadDigitArray<infer THeadDigits, infer TLastDigit> ? A extends TLastDigit ? 1 : B extends TLastDigit ? -1 : _CompareDigits<A, B, THeadDigits> : never);
declare type CompareFloatMagnitudes<X extends UnsignedFloat, Y extends UnsignedFloat> = (Normalise<X, Y> extends [...DigitsPair<infer TNormalisedX, infer TNormalisedY>, number] ? CompareMagnitudes<TNormalisedX, TNormalisedY> : never);
declare type CompareIntMagnitudes<X extends Digit[], Y extends Digit[]> = (NormaliseIntPartLengths<X, Y> extends DigitsPair<infer TNormalisedX, infer TNormalisedY> ? CompareMagnitudes<TNormalisedX, TNormalisedY> : never);
declare type CompareLengths<A extends unknown[], B extends unknown[]> = (A['length'] extends B['length'] ? 0 : A['length'] extends 0 ? -1 : B['length'] extends 0 ? 1 : CompareLengths<Head<A>, Head<B>>);
declare type CompareMagnitudes<TNormalisedX extends Digit[], TNormalisedY extends Digit[]> = (TNormalisedX extends TNormalisedY ? 0 : [TNormalisedX, TNormalisedY] extends [TailDigitArray<infer XFirst, infer XTail>, TailDigitArray<infer YFirst, infer YTail>] ? CompareDigits<XFirst, YFirst> extends 0 ? CompareMagnitudes<XTail, YTail> : CompareDigits<XFirst, YFirst> : never);
declare type _CompareMap = {
[K in ComparisonResult]: unknown;
};
declare type CompareNumberMagnitudes<X extends number, Y extends number> = (SplitAndNormalise<X, Y> extends [...DigitsPair<infer TNormalisedX, infer TNormalisedY>, number] ? CompareMagnitudes<TNormalisedX, TNormalisedY> : never);
declare type ComparisonResult = -1 | 0 | 1;
declare type CrossMultiply<X extends Digit[], Y extends Digit[], TShift extends 0[] = [], TPrevRowResult extends Digit[] = []> = (Y extends HeadDigitArray<infer YHead, infer B> ? CrossMultiply<X, YHead, [...TShift, 0], NormaliseIntZeros<AddUnsignedInts<TPrevRowResult, [
...MultiplyRow<X, B>,
...TShift
]>>> : TPrevRowResult);
declare type DecomposeNum<S extends string | number> = (SeparateSign<`${S}`> extends [infer TSign extends Sign, infer M extends string] ? SplitIntAndFractionParts<ScientificNotationAsDecimal<M>> extends NumComponents<never, infer I, infer F> ? NumComponents<TSign, TrimLeadingZeros<I>, TrimTrailingZeros<F>> : never : never);
declare type Digit = OrderedDigits[number];
declare type DigitsPair<TDigits1 extends Digit[], TDigits2 extends Digit[]> = [TDigits1, TDigits2];
declare type DigitsToUnsignedFloat<X extends Digit[], TDecimalPlaces extends number, TFractionalDigits extends Digit[] = []> = (TFractionalDigits['length'] extends TDecimalPlaces ? MakeUnsignedFloat<X, TFractionalDigits> : X extends HeadDigitArray<infer XHead, infer XLast> ? DigitsToUnsignedFloat<XHead, TDecimalPlaces, [XLast, ...TFractionalDigits]> : never);
declare type DigitwiseAdd<TNormalisedX extends Digit[], TNormalisedY extends Digit[]> = DigitwiseAdditiveOp<AdditionTable, TNormalisedX, TNormalisedY>;
declare type DigitwiseAdditiveOp<TTable extends AdditiveOperationTable, X extends Digit[], Y extends Digit[], TCarryIn extends Bit = 0, TFinalResult extends Digit[] = []> = ([
X,
Y
] extends [HeadDigitArray<infer XHead, infer A>, HeadDigitArray<infer YHead, infer B>] ? TTable[TCarryIn][A] extends AdditiveOperationResult<infer TCarryOut1, infer AAndCarryIn> ? TTable[B][AAndCarryIn] extends AdditiveOperationResult<infer TCarryOut2, infer TResult> ? DigitwiseAdditiveOp<TTable, XHead, YHead, Or<TCarryOut1, TCarryOut2>, [TResult, ...TFinalResult]> : never : never : [TCarryIn, ...TFinalResult]);
declare type DigitwiseSubtract<TNormalisedX extends Digit[], TNormalisedY extends Digit[]> = DigitwiseAdditiveOp<SubtractionTable, TNormalisedX, TNormalisedY>;
/**
* Divide two numeric type literals.
*
* @param TNumerator - The numerator (a.k.a dividend)
* @param TDivisor - The divisor (a.k.a denominator)
* @returns TNumerator / TDivisor
*
* @public
*/
export declare type Divide<TNumerator extends number, TDivisor extends number> = (SomeElementExtends<[TNumerator, TDivisor], never> extends 1 ? never : TDivisor extends 0 ? never : TNumerator extends 0 ? 0 : TDivisor extends 1 ? TNumerator : number extends (TNumerator | TDivisor) ? number : TDivisor extends -1 ? Negate<TNumerator> : DivideNumbers<TNumerator, TDivisor>);
declare type DivideMaxDigits = 13;
declare type DivideNumbers<TNumerator extends number, TDivisor extends number> = SignedFloatToNum<DivideSignedFloats<ToSignedFloat<TNumerator>, ToSignedFloat<TDivisor>>>;
declare type DivideSignedFloats<TNumerator extends SignedFloat, TDivisor extends SignedFloat> = (TNumerator extends SignedFloat<infer NSign, infer N> ? TDivisor extends SignedFloat<infer DSign, infer D> ? SignedFloat<MultiplySigns<NSign, DSign>, DivideUnsignedFloats<N, D>[0]> : never : never);
declare type DivideUnsignedFloats<TNumerator extends UnsignedFloat, TDivisor extends UnsignedFloat, TWithRemainder extends boolean = false> = (Normalise<TNumerator, TDivisor> extends [...DigitsPair<infer N, infer D>, infer TDecimalPlaces] ? N extends TailDigitArray<infer TNumeratorHead, infer TNumeratorTail> ? [
LongDivide<D, [TNumeratorHead], TNumeratorTail, [], TWithRemainder>,
TDecimalPlaces
] : never : never);
declare type EmptryStringAsZero<S extends string> = S extends '' ? '0' : S;
/**
* Perform an equality comparison on two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns Bit - (1 if X \< Y, 0 if X \>= Y).
*
* @public
*/
export declare type Eq<X extends number, Y extends number> = (SomeElementExtends<[X, Y], never> extends 1 ? never : number extends (X | Y) ? Bit : X extends Y ? Y extends X ? 1 : 0 : 0);
declare type EuclideanDivide<TNumerator extends Digit[], TDivisor extends Digit[]> = _EuclideanDivide<TDivisor, TNumerator, [0]>;
declare type _EuclideanDivide<TDivisor extends Digit[], TRemainder extends Digit[], TQuotient extends Digit[]> = (CompareIntMagnitudes<TRemainder, TDivisor> extends (1 | 0) ? _EuclideanDivide<TDivisor, SubtractUnsignedInts<TRemainder, TDivisor>, AddUnsignedInts<TQuotient, [1]>> : MakeModResult<TRemainder, TQuotient>);
declare type EuclideanDivideResult<TRemainder extends Digit[], TQuotient extends Digit> = ModResult<TRemainder, [TQuotient]>;
declare type Exponentiate<X extends number, N extends number> = (N extends 0 ? 1 : IsNegative<N> extends 1 ? Exponentiate<Divide<1, X>, Negate<N>> : IsEven<N> extends 1 ? Exponentiate<Multiply<X, X>, Divide<N, 2>> : Exponentiate<Multiply<X, X>, Divide<Subtract<N, 1>, 2>> extends infer XX extends number ? Multiply<X, XX> : never);
declare type FirstAdditiveResultRow = MakeFirstRow<[]>;
declare type FlipSign<S extends Sign> = SignMap<'+', '-'>[S];
declare type FloatDigitCount<TUnsignedFloat extends UnsignedFloat> = ([
...TUnsignedFloat[0],
...TUnsignedFloat[1]
] extends infer TDigits extends Digit[] ? TDigits['length'] : never);
declare type FloatMaxDigits = 16;
declare type FloatMaxDigitsAsUnsignedFloat = ToUnsignedFloat<FloatMaxDigits>;
declare type FourBits = [Bit, Bit, Bit, Bit];
declare type GetSign<N extends number> = BitMap<'-', '+'>[IsPositive<N>];
/**
* Perform a 'greater than' comparison on two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns Bit - (1 if X \> Y, 0 if X \<= Y).
*
* @public
*/
export declare type Gt<X extends number, Y extends number> = (CompareDecisionBranch<X, Y, {
[-1]: 0;
0: 0;
1: 1;
}>);
/**
* Perform a 'greater than or equal to' operation on two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns Bit - (1 if X \>= Y, 0 if X \< Y).
*
* @public
*/
export declare type GtOrEq<X extends number, Y extends number> = (CompareDecisionBranch<X, Y, {
[-1]: 0;
0: 1;
1: 1;
}>);
declare type Head<A extends unknown[]> = A extends [...infer THead, unknown] ? THead : never;
declare type HeadDigitArray<THead extends Digit[], TLast extends Digit> = [...THead, TLast];
declare type InferNum<S extends string, TSign extends Sign> = (S extends '0' ? 0 : `${SignStr<TSign>}${S}` extends `${infer N extends number}` ? N : never);
/**
* Checks if a numeric type literal is Even.
*
* @param N - The number to check.
* @returns Bit - (i.e. 1 if N is Even, 0 if N is Odd. Returns never if N is has a non-zero fractional component).
*
* @public
*/
export declare type IsEven<N extends number> = (number extends N ? Bit : N extends N ? IsUnsignedFloatEven<ToUnsignedFloat<N>> : never);
/**
* Checks if a numeric type literal is an Integer.
*
* @param N - The number to check.
* @returns Bit - (i.e. 1 if N is an Integer, 0 if N has a non-zero fractional component).
*
* @public
*/
export declare type IsInt<N extends number> = (number extends N ? Bit : N extends N ? `${N}` extends `${string}.${string}` ? 0 : 1 : never);
declare type IsIntEven<D extends Digit[]> = (D extends HeadDigitArray<any, infer TLastDigit> ? TLastDigit extends (0 | 2 | 4 | 6 | 8) ? 1 : 0 : never);
/**
* Check if a numeric literal is negative.
*
* @param N - The number to check.
* @returns Bit (i.e. 1 if N is negative, 0 if N is positive).
*
* @public
*/
export declare type IsNegative<N extends number> = Not<IsPositive<N>>;
/**
* Checks if a numeric type literal is not an Integer.
*
* @param N - The number to check.
* @returns Bit - (i.e. 1 if N has a non-zero fractional component, 0 if N is an Integer).
*
* @public
*/
export declare type IsNotInt<N extends number> = Not<IsInt<N>>;
/**
* Checks if a numeric type literal is Odd.
*
* @param N - The number to check.
* @returns Bit - (i.e. 1 if N is Odd, 0 if N is Even. Returns never if N is has a non-zero fractional component).
*
* @public
*/
export declare type IsOdd<N extends number> = Not<IsEven<N>>;
/**
* Check if a numeric literal is positive.
*
* @param N - The number to check.
* @returns Bit (i.e. 1 if N is positive, 0 if N is negative).
*
* @public
*/
export declare type IsPositive<N extends number> = (N extends N ? number extends N ? Bit : `${N}` extends `-${number}` ? 0 : 1 : never);
declare type IsUnsignedFloatEven<F extends UnsignedFloat> = (F[1] extends [] ? IsIntEven<F[0]> : never);
declare type Join<A extends Stringable[], S extends string = ''> = (A extends [infer H extends Stringable, ...infer R extends Stringable[]] ? Join<R, `${S}${H}`> : S);
declare type Last<A extends unknown[]> = A extends [...unknown[], infer TLast] ? TLast : never;
declare type LeftPad<A extends unknown[], V, N extends number> = (A['length'] extends N ? A : LeftPad<[V, ...A], V, N>);
declare type LeftTrimTuple<A extends unknown[], T> = (A extends [infer H, ...infer R] ? [H] extends [T] ? LeftTrimTuple<R, T> : A : A);
declare type LongDivide<TDivisor extends Digit[], TNumeratorHead extends Digit[], TNumeratorTail extends Digit[], TQuotient extends Digit[] = [], TWithRemainder extends boolean = false> = (EuclideanDivide<TNumeratorHead, TDivisor> extends EuclideanDivideResult<infer TRemainder, infer TNextQuotientDigit> ? [...TQuotient, TNextQuotientDigit] extends infer TNextQuotient extends Digit[] ? TNumeratorTail extends TailDigitArray<infer TNextDigit, infer TNextTail> ? LongDivide<TDivisor, [...TRemainder, TNextDigit], TNextTail, TNextQuotient, TWithRemainder> : TWithRemainder extends false ? MakeUnsignedFloat<TNextQuotient, TRemainder extends [0] ? [] : LongDivideFraction<TDivisor, [...TRemainder, 0]>> : MakeModResult<TRemainder, TNextQuotient> : never : never);
declare type LongDivideFraction<TDivisor extends Digit[], TNumerator extends Digit[], TQuotient extends Digit[] = []> = (_Compare<TQuotient['length'], DivideMaxDigits> extends 1 ? TQuotient : EuclideanDivide<TNumerator, TDivisor> extends EuclideanDivideResult<infer TRemainder, infer TNextQuotientDigit> ? TRemainder extends [0] ? [...TQuotient, TNextQuotientDigit] : LongDivideFraction<TDivisor, [...TRemainder, 0], [...TQuotient, TNextQuotientDigit]> : never);
/**
* Perform a 'less than' comparison on two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns Bit - (1 if X \< Y, 0 if X \>= Y).
*
* @public
*/
export declare type Lt<X extends number, Y extends number> = Gt<Y, X>;
/**
* Perform a 'less than or equal to' operation on two numeric type literals.
*
* @param X - The number on the "left".
* @param Y - The number on the "right".
* @returns Bit - (1 if X \<= Y, 0 if X \> Y).
*
* @public
*/
export declare type LtOrEq<X extends number, Y extends number> = GtOrEq<Y, X>;
declare type MakeAdditionTable<T extends unknown[]> = (T['length'] extends 10 ? T : MakeAdditionTable<[...T, RotateLeftWithCarry<Last<T>>]>);
declare type MakeFirstRow<A extends AdditiveOperationResult[]> = (A['length'] extends Digit ? MakeFirstRow<[...A, AdditiveOperationResult<0, A['length']>]> : A);
declare type MakeModResult<TRemainder extends Digit[], TQuotient extends Digit[]> = ModResult<NormaliseIntZeros<TRemainder>, NormaliseIntZeros<TQuotient>>;
declare type MakeMultiplicationRow<N extends Digit, TRow extends number[] = [0]> = (TRow['length'] extends 10 ? TRow : Last<TRow> extends infer TPrev extends number ? MakeMultiplicationRow<N, [...TRow, Add<TPrev, N>]> : never);
declare type MakeMultiplicationTable<TTable extends unknown[], X extends Digit[]> = (TTable['length'] extends 10 ? TTable : X extends TailDigitArray<infer N, infer XTail> ? MakeMultiplicationTable<[...TTable, MapToOperationResult<MakeMultiplicationRow<N>>], XTail> : never);
declare type MakeSignedFloat<TSign extends Sign, TUnsignedFloat extends UnsignedFloat> = (MakeUnsignedFloat<TUnsignedFloat[0], TUnsignedFloat[1]> extends infer TActualUnsignedFloat extends UnsignedFloat ? TActualUnsignedFloat extends UnsignedFloatZero ? SignedFloatZero : SignedFloat<TSign, TActualUnsignedFloat> : never);
declare type MakeSubtractionTable<T extends unknown[]> = (T['length'] extends 10 ? T : MakeSubtractionTable<[...T, RotateRightWithCarry<Last<T>>]>);
declare type MakeUnsignedFloat<TIntegerDigits extends Digit[], TFractionalDigits extends Digit[] = []> = (UnsignedFloat<NormaliseIntZeros<TIntegerDigits>, NormaliseFractionalZeros<TFractionalDigits>>);
declare type MapToOperationResult<TRow extends number[]> = {
[K in keyof TRow]: OperationResultFromNum<TRow[K]>;
};
/**
* Get the greatest of two numeric type literals.
*
* @param X - The first operand.
* @param Y - The second operand.
* @returns X|Y - (X if X \> Y, Y if Y \> X else X (since they would be equal)).
*
* @public
*/
export declare type Max<X extends number, Y extends number> = (number extends (X | Y) ? number : X extends Y ? X : Y extends X ? Y : Gt<X, Y> extends 1 ? X : Y);
/**
* Get the smallest of two numeric type literals.
*
* @param X - The first operand.
* @param Y - The second operand.
* @returns X|Y - (X if X \< Y, Y if Y \< X else X (since they would be equal)).
*
* @public
*/
export declare type Min<X extends number, Y extends number> = (number extends (X | Y) ? number : X extends Y ? X : Y extends X ? Y : Lt<X, Y> extends 1 ? X : Y);
/**
* Mod two numeric type literals. This returns the remainder as per JavaScript's Remainder (%) operator.
*
* @param TNumerator - The numerator (a.k.a dividend)
* @param TDivisor - The divisor (a.k.a denominator)
* @returns TNumerator % TDivisor
*
* @public
*/
export declare type Mod<TNumerator extends number, TDivisor extends number> = (SomeElementExtends<[TNumerator, TDivisor], never> extends 1 ? never : TDivisor extends 0 ? never : TNumerator extends 0 ? 0 : number extends (TNumerator | TDivisor) ? number : ModNumbers<TNumerator, TDivisor>);
declare type ModNumbers<TNumerator extends number, TDivisor extends number> = SignedFloatToNum<ModSignedFloats<ToSignedFloat<TNumerator>, ToSignedFloat<TDivisor>>>;
declare type ModResult<TRemainder extends Digit[], TQuotient extends Digit[]> = [
remainder: TRemainder,
quotient: TQuotient
];
declare type ModSignedFloats<TNumerator extends SignedFloat, TDivisor extends SignedFloat> = (TNumerator extends SignedFloat<infer NSign, infer N> ? TDivisor extends SignedFloat<Sign, infer D> ? SignedFloat<NSign, ModUnsignedFloats<N, D>> : never : never);
declare type ModUnsignedFloats<TNumerator extends UnsignedFloat, TDivisor extends UnsignedFloat> = (DivideUnsignedFloats<TNumerator, TDivisor, true> extends [ModResult<infer TRemainder, infer TQuotient>, infer TDecimalPlaces extends number] ? SafeDigitsToUnsignedFloat<TRemainder, TDecimalPlaces> : never);
declare type MultiplicationTable = MakeMultiplicationTable<[], OrderedDigits>;
/**
* Multiply two numeric type literals.
*
* @param X - The first operand.
* @param Y - The second operand.
* @returns X * Y
*
* @public
*/
export declare type Multiply<X extends number, Y extends number> = (SomeElementExtends<[X, Y], never> extends 1 ? never : X extends 0 ? 0 : Y extends 0 ? 0 : X extends 1 ? Y : Y extends 1 ? X : number extends (X | Y) ? number : X extends -1 ? Negate<Y> : Y extends -1 ? Negate<X> : MultiplyNumbers<X, Y>);
declare type MultiplyNumbers<X extends number, Y extends number> = SignedFloatToNum<MultiplySignedFloats<ToSignedFloat<X>, ToSignedFloat<Y>>>;
declare type MultiplyRow<X extends Digit[], B extends Digit, TCarryIn extends Digit = 0, TFinalResult extends Digit[] = []> = (X extends HeadDigitArray<infer XHead, infer A> ? MultiplicationTable[A][B] extends OperationResult<infer ATimesBCarryOut, infer ATimesB> ? AdditionTable[ATimesB][TCarryIn] extends AdditiveOperationResult<infer TCarryOut2, infer TResult> ? AdditionTable[ATimesBCarryOut][TCarryOut2] extends AdditiveOperationResult<0, infer TFinalCarryOut> ? MultiplyRow<XHead, B, TFinalCarryOut, [TResult, ...TFinalResult]> : never : never : never : [TCarryIn, ...TFinalResult]);
declare type MultiplySignedFloats<X extends SignedFloat, Y extends SignedFloat> = (X extends SignedFloat<infer XSign, infer XUnsignedFloat> ? Y extends SignedFloat<infer YSign, infer YUnsignedFloat> ? SignedFloat<MultiplySigns<XSign, YSign>, MultiplyUnsignedFloats<XUnsignedFloat, YUnsignedFloat>> : never : never);
declare type MultiplySigns<S extends Sign, T extends Sign> = SignMultiplicationMap[S][T];
declare type MultiplyUnsignedFloats<X extends UnsignedFloat, Y extends UnsignedFloat> = (NormaliseForCrossMultiply<X, Y> extends [...DigitsPair<infer TNormalisedX, infer TNormalisedY>, infer TDecimalPlaces extends number] ? SafeDigitsToUnsignedFloat<CrossMultiply<TNormalisedX, TNormalisedY>, TDecimalPlaces> : never);
/**
* Negate a numeric literal
*
* @param N - The number to negate.
* @returns -N
*
* @public
*/
export declare type Negate<N extends number> = (N extends 0 ? 0 : number extends N ? number : `${N}` extends `-${infer M extends number}` ? M : `-${N}` extends `${infer M extends number}` ? M : never);
declare type NegateSignedFloat<X extends SignedFloat> = (X extends SignedFloat<infer TSign, infer TUnsignedFloat> ? SignedFloat<FlipSign<TSign>, TUnsignedFloat> : never);
declare type Normalise<X extends UnsignedFloat, Y extends UnsignedFloat> = (NormaliseIntPartLengths<X[0], Y[0]> extends DigitsPair<infer XIntegerPart, infer YIntegerPart> ? NormaliseLengths<X[1], Y[1], 'R', 0> extends DigitsPair<infer XFractionalPart, infer YFractionalPart> ? [
xDigits: [...XIntegerPart, ...XFractionalPart],
yDigits: [...YIntegerPart, ...YFractionalPart],
decimalPlaces: YFractionalPart['length']
] : never : never);
declare type NormaliseForCrossMultiply<X extends UnsignedFloat, Y extends UnsignedFloat> = (X extends UnsignedFloat<infer XIntegerPart, infer XFractionalPart> ? Y extends UnsignedFloat<infer YIntegerPart, infer YFractionalPart> ? [
xDigits: NormaliseIntZeros<[...XIntegerPart, ...XFractionalPart]>,
yDigits: NormaliseIntZeros<[...YIntegerPart, ...YFractionalPart]>,
decimalPlaces: AddNumbers<XFractionalPart['length'], YFractionalPart['length']>
] : never : never);
declare type NormaliseFractionalZeros<X extends Digit[]> = RightTrimTuple<X, 0>;
declare type NormaliseIntPartLengths<X extends Digit[], Y extends Digit[]> = NormaliseLengths<X, Y, 'L', 0>;
declare type NormaliseIntZeros<X extends Digit[]> = (LeftTrimTuple<X, 0> extends infer TTrimmedX extends Digit[] ? TTrimmedX extends [] ? [0] : TTrimmedX : never);
declare type NormaliseLengths<A extends unknown[], B extends unknown[], D extends PadDirection, TPadValue> = (CompareLengths<A, B> extends 0 | -1 ? [Pad<D, A, TPadValue, B['length']>, B] : [A, Pad<D, B, TPadValue, A['length']>]);
/**
* Perform an NOT operation on a Bit literals.
*
* @param B - The operand to NOT.
* @returns Bit - (~B)
*
* @public
*/
export declare type Not<B extends Bit> = NotMap[B];
declare type NotMap = BitMap<1, 0>;
declare type NumComponents<TSign extends Sign, I extends string, F extends string> = [
sign: EmptryStringAsZero<I | F> extends '0' ? '+' : TSign,
integerPart: I,
fractionalPart: F
];
declare type NumsUpto<N extends number, A extends number[] = []> = (A['length'] extends N ? Reject<A, never> : NumsUpto<N, [...A, A['length']]>);
declare type OperationResult<C extends Digit = Digit, R extends Digit = Digit> = [carry: C, result: R];
declare type OperationResultFromNum<N extends number> = (`${N}` extends `${infer C extends Digit}${infer R extends Digit}` ? OperationResult<C, R> : `${N}` extends `${infer R extends Digit}` ? OperationResult<0, R> : never);
/**
* Perform an OR operation on two Bit literals.
*
* @param A - The first operand.
* @param B - The second operand.
* @returns Bit - (A | B)
*
* @public
*/
export declare type Or<A extends Bit, B extends Bit> = OrMap[A][B];
declare type OrderedDigits = NumsUpto<10>;
declare type OrMap = TwoBitMap<[0, 1, 1, 1]>;
declare type Pad<D extends PadDirection, A extends unknown[], V, N extends number> = {
'L': LeftPad<A, V, N>;
'R': RightPad<A, V, N>;
}[D];
declare type PadDirection = 'L' | 'R';
/**
* Raise a numeric literal to the power of another.
*
* @param X - The base.
* @param N - The exponent (a.k.a power). Must be an Integer.
* @returns X^N
*
* @public
*/
export declare type Pow<X extends number, N extends number> = (SomeElementExtends<[X, N], never> extends 1 ? never : N extends 0 ? 1 : N extends 1 ? X : X extends 1 ? 1 : X extends -1 ? number extends N ? -1 | 1 : PowRejectingFractionalExponent<X, N> : X extends 0 ? IsNegative<N> extends 1 ? never : 0 : number extends (X | N) ? number : PowRejectingFractionalExponent<X, N>);
declare type PowRejectingFractionalExponent<X extends number, N extends number> = (IsInt<N> extends 0 ? never : Exponentiate<X, N>);
declare type Reject<A extends unknown[], T> = (A extends [infer H, ...infer R] ? [H] extends [T] ? Reject<R, T> : [H, ...Reject<R, T>] : []);
declare type RightPad<A extends unknown[], V, N extends number> = (A['length'] extends N ? A : RightPad<[...A, V], V, N>);
declare type RightTrimTuple<A extends unknown[], T> = (A extends [...infer H, infer L] ? [L] extends [T] ? RightTrimTuple<H, T> : A : A);
declare type RotateLeftWithCarry<A> = (A extends [AdditiveOperationResult<any, infer R>, ...infer TTail] ? [...TTail, AdditiveOperationResult<1, R>] : never);
declare type RotateRightWithCarry<A> = (A extends [...infer THead, AdditiveOperationResult<any, infer R>] ? [AdditiveOperationResult<1, R>, ...THead] : never);
declare type RoundFloat<F extends SignedFloat> = (SmallEnoughForScientificNotation<F[1][1]> extends 1 ? F : F extends SignedFloat<infer TSign, infer FUnsignedFloat> ? _Compare<FloatDigitCount<FUnsignedFloat>, FloatMaxDigits> extends (-1 | 0) ? F : SubtractUnsignedFloats<FloatMaxDigitsAsUnsignedFloat, ToUnsignedFloat<FUnsignedFloat[0]['length']>> extends SignedFloat<infer TTargetFractionLengthSign, infer TTargetFractionLength> ? TTargetFractionLengthSign extends '-' ? F : RoundFractionalDigits<FUnsignedFloat[1], RoundingCarryMap[TSign], UnsignedFloatToNum<TTargetFractionLength, '+'>> extends [infer TCarryOut extends Digit, ...infer TRoundedFraction extends Digit[]] ? MakeSignedFloat<TSign, UnsignedFloat<AddUnsignedInts<FUnsignedFloat[0], [TCarryOut]>, TRoundedFraction>> : never : never : never);
declare type RoundFractionalDigits<F extends Digit[], TRoundingMap extends Digit[], TTargetFractionLength extends number> = (F extends HeadDigitArray<infer FHead, infer D> ? FHead['length'] extends TTargetFractionLength ? TTargetFractionLength extends 0 ? [TRoundingMap[D]] : AddUnsignedInts<FHead, [TRoundingMap[D]]> : RoundFractionalDigits<FHead, TRoundingMap, TTargetFractionLength> : never);
declare type RoundingCarryMap = SignMap<[
...ArrayOf<6, 0>,
...ArrayOf<4, 1>
], [
...ArrayOf<5, 0>,
...ArrayOf<5, 1>
]>;
declare type SafeDigitsToUnsignedFloat<X extends Digit[], TDecimalPlaces extends number, TFractionalDigits extends Digit[] = []> = (_Compare<X['length'], TDecimalPlaces> extends -1 ? DigitsToUnsignedFloat<LeftPad<X, 0, TDecimalPlaces>, TDecimalPlaces> : DigitsToUnsignedFloat<X, TDecimalPlaces>);
declare type ScientificNotationAsDecimal<N extends string | number> = (`${N}` extends `${infer TSignificand extends number}e-${infer TExp extends number}` ? SplitIntAndFractionParts<TSignificand> extends NumComponents<never, infer I, infer F> ? ArrayOf<TExp, 0> extends [infer TIntZero extends 0, ...infer TFractionZeros extends 0[]] ? Join<[TIntZero, '.', ...TFractionZeros, I, F]> : never : never : `${N}`);
declare type SeparateSign<S extends string> = (S extends `-${infer N}` ? ['-', N] : ['+', S]);
declare type Sign = '+' | '-';
declare type SignDecisionBranch<X extends number, Y extends number, TBranches extends SignMap<SignMap, SignMap>> = TBranches[GetSign<X>][GetSign<Y>];
declare type SignedFloat<TSign extends Sign = Sign, TUnsignedFloat extends UnsignedFloat = UnsignedFloat> = [
sign: TSign,
unsignedFloat: TUnsignedFloat
];
declare type SignedFloatToNum<TSignedFloat extends SignedFloat> = (RoundFloat<TSignedFloat> extends SignedFloat<infer TSign, infer TUnsignedFloat> ? UnsignedFloatToNum<TUnsignedFloat, TSign> : never);
declare type SignedFloatZero = SignedFloat<'+', UnsignedFloatZero>;
declare type SignMap<TNegative = unknown, TPositive = unknown> = {
'-': TNegative;
'+': TPositive;
};
declare type SignMultiplicationMap = SignMap<SignMap<'+', '-'>, SignMap<'-', '+'>>;
declare type SignStr<S extends Sign> = S extends '+' ? '' : S;
declare type SmallEnoughForScientificNotation<TFractionalDigits extends Digit[]> = (TFractionalDigits extends [0, 0, 0, 0, 0, 0, ...Digit[]] ? 1 : 0);
declare type SomeElementExtends<A extends unknown[], T> = (A extends [infer H, ...infer R] ? [H] extends [T] ? 1 : SomeElementExtends<R, T> : 0);
declare type SplitAndNormalise<X extends number, Y extends number> = Normalise<ToSignedFloat<X>[1], ToSignedFloat<Y>[1]>;
declare type SplitIntAndFractionParts<S extends string | number> = (`${S}` extends `${infer I}.${infer F}` ? NumComponents<never, I, F> : NumComponents<never, `${S}`, ''>);
declare type SplitIntoDigits<N extends string> = (N extends '' ? [] : N extends `${infer D extends Digit}${infer R}` ? R extends '' ? [D] : R extends `${number}` ? [D, ...SplitIntoDigits<R>] : never : never);
declare type SplitLeadingElements<A extends unknown[], T, L extends unknown[] = []> = (A extends [infer H, ...infer R] ? [H] extends [T] ? SplitLeadingElements<R, T, [...L, H]> : [L, A] : [L, []]);
declare type Stringable = string | number | bigint | boolean | null | undefined;
/**
* Perform subtraction on two numeric type literals.
*
* @param X - The first operand.
* @param Y - The second operand.
* @returns X - Y
*
* @public
*/
export declare type Subtract<X extends number, Y extends number> = (SomeElementExtends<[X, Y], never> extends 1 ? never : number extends (X | Y) ? number : X extends 0 ? Negate<Y> : Y extends 0 ? X : SubtractNumbers<X, Y>);
declare type SubtractionTable = MakeSubtractionTable<[FirstAdditiveResultRow]>;
declare type SubtractNumbers<X extends number, Y extends number> = SignedFloatToNum<SubtractSignedFloats<ToSignedFloat<X>, ToSignedFloat<Y>>>;
declare type SubtractSignedFloats<X extends SignedFloat, Y extends SignedFloat> = (X extends SignedFloat<infer XSign, infer XUnsignedFloat> ? Y extends SignedFloat<infer YSign, infer YUnsignedFloat> ? {
'-': {
'-': NegateSignedFloat<SubtractUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
'+': SignedFloat<'-', AddUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
};
'+': {
'-': SignedFloat<'+', AddUnsignedFloats<XUnsignedFloat, YUnsignedFloat>>;
'+': SubtractUnsignedFloats<XUnsignedFloat, YUnsignedFloat>;
};
}[XSign][YSign] : never : never);
declare type SubtractUnsignedFloats<X extends UnsignedFloat, Y extends UnsignedFloat> = {
1: SignedFloat<'+', _SubtractUnsignedFloats<X, Y>>;
0: SignedFloatZero;
[-1]: SignedFloat<'-', _SubtractUnsignedFloats<Y, X>>;
}[CompareFloatMagnitudes<X, Y>];
declare type _SubtractUnsignedFloats<X extends UnsignedFloat, Y extends UnsignedFloat> = (Normalise<X, Y> extends [...DigitsPair<infer TNormalisedX, infer TNormalisedY>, infer TDecimalPlaces extends number] ? DigitsToUnsignedFloat<DigitwiseSubtract<TNormalisedX, TNormalisedY>, TDecimalPlaces> : never);
declare type SubtractUnsignedInts<X extends Digit[], Y extends Digit[]> = (NormaliseIntPartLengths<X, Y> extends DigitsPair<infer TNormalisedX, infer TNormalisedY> ? DigitwiseSubtract<TNormalisedX, TNormalisedY> : never);
declare type TailDigitArray<TFirst extends Digit, TTail extends Digit[]> = [TFirst, ...TTail];
declare type ToDecimalString<TIntegerDigits extends Digit[], TFractionalDigits extends Digit[]> = (TFractionalDigits extends [] ? Join<TIntegerDigits> : `${Join<TIntegerDigits>}.${Join<TFractionalDigits>}`);
declare type ToSignedFloat<N extends number> = (DecomposeNum<N> extends NumComponents<infer TSign, infer I, infer F> ? SignedFloat<TSign, UnsignedFloat<SplitIntoDigits<I>, SplitIntoDigits<F>>> : never);
declare type ToSmallFractionString<TFractionalDigits extends Digit[]> = (SmallEnoughForScientificNotation<TFractionalDigits> extends 1 ? SplitLeadingElements<TFractionalDigits, 0> extends [infer TFractionalZeros extends 0[], infer TSignificand extends Digit[]] ? TSignificand extends TailDigitArray<infer TSignificandInt, infer TSignificandFraction> ? [0, ...TFractionalZeros]['length'] extends infer TExp extends number ? `${SignedFloatToNum<RoundFloat<SignedFloat<'+', [[TSignificandInt], TSignificandFraction]>>>}e-${TExp}` : never : never : never : ToDecimalString<[0], TFractionalDigits>);
declare type ToUnsignedFloat<N extends number> = ToSignedFloat<N>[1];
declare type Trim<S extends string, L extends string, R extends string> = ((L | R) extends '' ? S : '' extends (L | R) ? S extends `${L}${infer M}${R}` ? Trim<M, L, R> : S : never);
declare type TrimLeadingZeros<S extends string> = EmptryStringAsZero<Trim<S, '0', ''>>;
declare type TrimTrailingZeros<S extends string> = Trim<S, '', '0'>;
declare type TwoBitMap<R extends FourBits = FourBits> = BitMap<BitMap<R[0], R[1]>, BitMap<R[2], R[3]>>;
declare type UnsignedFloat<TIntegerDigits extends Digit[] = Digit[], TFractionalDigits extends Digit[] = Digit[]> = [
integerDigits: TIntegerDigits,
fractionalDigits: TFractionalDigits
];
declare type UnsignedFloatToNum<TUnsignedFloat extends UnsignedFloat, TSign extends Sign> = (TUnsignedFloat extends UnsignedFloat<infer TIntegerDigits, infer TFractionalDigits> ? TIntegerDigits extends [0] ? InferNum<ToSmallFractionString<TFractionalDigits>, TSign> : InferNum<ToDecimalString<TIntegerDigits, TFractionalDigits>, TSign> : never);
declare type UnsignedFloatZero = MakeUnsignedFloat<[0]>;
/**
* Perform an XOR (exclusive OR) operation on two Bit literals.
*
* @param A - The first operand.
* @param B - The second operand.
* @returns Bit - (A xor B)
*
* @public
*/
export declare type Xor<A extends Bit, B extends Bit> = XorMap[A][B];
declare type XorMap = TwoBitMap<[0, 1, 1, 0]>;
export { }