kakasoo

Math Types(2) - 타입으로 나누기, 나머지 연산 구현하기 본문

프로그래밍/TypeScript

Math Types(2) - 타입으로 나누기, 나머지 연산 구현하기

카카수(kakasoo) 2023. 4. 9. 19:11
반응형
 

Math Types(1) - 타입으로 사칙연산하기

타입스크립트 언어는 자바스크립트와 타입 레벨을 합친 언어다. 따라서 타입을 지정하는 것 뿐만 아니라 직접 타입을 구현할 수 있는 수준이 되어야 타입스크립트 쓰는 것이다. 하지만 타입 레

kscodebase.tistory.com

타입에서 나누기와 나머지 연산 구현하기

export type Divide<
    T extends number,
    N extends number,
    Answer extends number = 0
> = NTuple<T> extends [...NTuple<N>, ...infer Rest]
    ? Divide<Length<Rest>, N, NToNumber<Add<Answer, 1>>>
    : Answer;

export type Remainder<T extends number, N extends number> = Sub<
    T,
    NToNumber<Multiply<N, Divide<T, N>>>
>;

일단 이 두 식들을 이용하면 타입에서도 나누기와 나머지 연산을 쉽게 구현할 수 있다.
하지만 처음에 의도한대로, 이 타입들을 이용해서 너무 큰 튜플을 이용한 곱하기를 풀어 쓰는 방법은 힘들 것으로 보인다.
타입스크립트 내 튜플 길이의 한계는 999인데, 지금 이 타입들의 구현 방식 역시 곱하기를 사용하고 있기 때문이다.

 

타입에서 표현 가능한 튜플 길이는 999까지, NNTuple 수정하기

export type NNTuple<N1 extends number, N2 extends number> = Sub<
    N1,
    N2
> extends never
    ? Sub<N1, 1> extends never
        ? []
        : [...NNTuple<Sub<N1, 1>, N2>, ...NTuple<N2>]
    : Sub<N2, 1> extends never
    ? []
    : [...NNTuple<Sub<N2, 1>, N1>, ...NTuple<N1>];

따라서 이전에 구현한 NNTuple도 수정해주었다.

이는 전개 연산 방식에 따라 2 * 999는 가능한데, 999 * 2가 불가능한 경우들을 해결하기 위함이다.

전개 연산을 재귀적으로 하다가 어느 시점 튜플의 크기가 1,000 이상이 될 때 타입스크립트 서버는 이를 허용하지 않기 때문이다.

아예 방법이 없는 것은 아닌 게, 타입 안에서의 전개 연산의 경우 일부지만 분명히 허용이 되고 있다.
이걸 이용하면 이론 상 가능은... 하다

 

이론 상은 가능한데 난 안 할래...

export type SuperAdd<T extends number[]> = Length<T> extends 0
    ? 0
    : Length<T> extends 1
    ? Length<[...NTuple<T[0]>]>
    : Length<T> extends 2
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>]>
    : Length<T> extends 3
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>]>
    : Length<T> extends 4
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>]>
    : Length<T> extends 5
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>, ...NTuple<T[4]>]>
    : Length<T> extends 6
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>, ...NTuple<T[4]>, ...NTuple<T[5]>]>
    : Length<T> extends 7
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>, ...NTuple<T[4]>, ...NTuple<T[5]>, ...NTuple<T[6]>]>
    : Length<T> extends 8
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>, ...NTuple<T[4]>, ...NTuple<T[5]>, ...NTuple<T[6]>, ...NTuple<T[7]>]>
    : Length<T> extends 9
    ? Length<[...NTuple<T[0]>, ...NTuple<T[1]>, ...NTuple<T[2]>, ...NTuple<T[3]>, ...NTuple<T[4]>, ...NTuple<T[5]>, ...NTuple<T[6]>, ...NTuple<T[7]>, ...NTuple<T[8]>]>
    : never;

type Answer = SuperAdd<[999, 999, 999, 999, 999, 999, 999, 999, 999]>;

어떠한 수 A, B를 곱해야 할 때, A와 B가 둘 다 999 이하의 숫자라고 가정한다면,

A가 B번 전개 연산을 하여 숫자를 만든다고 할 때 파라미터의 최대 크기는 999이며 이 둘의 곱인 999 * 999가 표현 가능한 수가 된다.

그리고 만약 999보다 큰 수가 들어올 때, 그 수를 1000보다 작아지게끔 여러 횟수로 분해한다면?

예를 들어 1,000과 1의 덧셈은 불가능하지만, 999와 1, 1, 이렇게 세 수의 합은 가능하기 때문에 분해한 수의 종류가 999 이하면 된다.

어쨌거나 최대 표현 치인 999 * 999가 가능해지기는 하다.

물론 이걸 한다고 해도 최대 표현 치가 998,001 정도로 매우 작기 때문에 어차피 문제 해결이 된 것은 아니다.

 

반응형