32532-hard-binary-addition

Back

// Add one to A
// eg.
// AddOne<[1, 0]> -> [1, 1]
// AddOne<[1, 1]> -> [1, 0, 0]
type AddOne<A extends Bit[]> = A extends [...infer Rest extends Bit[], infer Last]
  ? Last extends 0
    ? [...Rest, 1]
    : [...AddOne<Rest>, 0]
  : [1];

type BinaryAdd<A extends Bit[], B extends Bit[]> = B extends [...infer BRest extends Bit[], infer BLast]
  ? BLast extends 1
    ? AddOne<A> extends [...infer ARest extends Bit[], infer ALast]
      ? [...BinaryAdd<ARest, BRest>, ALast]
      : never
    : A extends [...infer ARest extends Bit[], infer ALast]
    ? [...BinaryAdd<ARest, BRest>, ALast]
    : B
  : A;

Solution by yukicountry #34437

type Bit = 1 | 0

type CarryBit<A extends Bit, B extends Bit, PreviousCarry extends Bit> =
  `${A}${B}${PreviousCarry}` extends `${any}1${any}1${any}` ? 1 : 0

type AddBit<A extends Bit, B extends Bit, PreviousCarry extends Bit> =
  `${A}${B}${PreviousCarry}` extends `111` ? 1 :
  `${A}${B}${PreviousCarry}` extends `${any}1${any}1${any}` ? 0 :
  `${A}${B}${PreviousCarry}` extends `${any}1${any}` ? 1 : 0

type BinaryAdd<A extends Bit[], B extends Bit[], Carry extends Bit = 0, FinalArray extends Bit[] = []> =
  A extends [...infer RestOfA extends Bit[], infer LastBitA extends Bit] ?
    B extends [...infer RestOfB extends Bit[], infer LastBitB extends Bit] ?
      BinaryAdd<RestOfA, RestOfB, CarryBit<LastBitA, LastBitB, Carry>, [AddBit<LastBitA, LastBitB, Carry>, ...FinalArray]> :
      // assumption that the binary arrays are same length so will never get to this never type
      never :
    Carry extends 1 ?
      [1, ...FinalArray] :
      FinalArray

Solution by M-Kusumgar #33729

Support A's length is not equal to B's length.

// your answers
type Bit = 1 | 0

type LastBit<T extends Bit[]> = T extends [...Bit[], infer B extends Bit] ? B : never
type PoppedBits<T extends Bit[]> = T extends [...infer Rest extends Bit[], Bit] ? Rest : never
type FilterOne<T extends Bit[]> = T extends [] ? [] : [...(LastBit<T> extends 0 ? [] : [1]), ...FilterOne<PoppedBits<T>>]
type NumOfOne<T extends Bit[]> = FilterOne<T>['length']

type BinaryAdd<
  A extends Bit[], 
  B extends Bit[],
  Carry extends Bit = 0,
  Result extends Bit[] = [],
  // Internals
  CurrentBitA extends Bit = LastBit<A>,
  CurrentBitB extends Bit = LastBit<B>,
  CurrentBitResult extends Bit = NumOfOne<[CurrentBitA, CurrentBitB, Carry]> extends (0 | 2) ? 0 : 1,
  NextA extends Bit[] = PoppedBits<A> extends [] ? [0] : PoppedBits<A>,
  NextB extends Bit[] = PoppedBits<B> extends [] ? [0] : PoppedBits<B>,
  NextCarry extends Bit = NumOfOne<[CurrentBitA, CurrentBitB, Carry]> extends (2 | 3) ? 1 : 0,
> = [A, B, Carry] extends [[0], [0], 0]
  ? Result
  : BinaryAdd<
      NextA,
      NextB,
      NextCarry,
      [CurrentBitResult, ...Result]
    >

Solution by DevilTea #33275

To restrict the number of recursions, assuming length of A >= length of B

type Bit = 1 | 0

type BinaryAdd<A extends Bit[], B extends Bit[],
  Sum extends Bit[] = {[I in keyof A]: [A[I], B[I & keyof B]] extends [1, 0] | [0, 1] ? 1 : 0},
  Carry extends Bit[] = {[I in keyof A]: [A[I], B[I & keyof B]] extends [1, 1] ? 1 : 0}
> = Carry extends [1, ...any] ? BinaryAdd<[...Carry, 0], [0, ...Sum]>
  : Carry extends [any, 1, ...any] ? BinaryAdd<Carry, Sum>
  : Sum

Playground

Solution by teamchong #32986

type Bit = 1 | 0;
type Shifts = '011' | '101' | '110' | '111';
type Ones = '001' | '010' | '100' | '111';

type BinaryAdd<A extends Bit[], B extends Bit[], S extends Bit = 0, R extends Bit[] = []> = 
  [A, B] extends [[...infer AR extends Bit[], infer X extends Bit], [...infer BR extends Bit[], infer Y extends Bit]]
    ? BinaryAdd<AR, BR, `${S}${X}${Y}` extends Shifts ? 1 : 0, [`${S}${X}${Y}` extends Ones ? 1 : 0, ...R]>
    : S extends 1 ? [1, ...R] : R;

Solution by alexandroppolus #32964

type Bit = 1 | 0

type Single<A extends Bit, B extends Bit, Carry extends boolean = false> =
  `${A}${B}` extends `11`
    ?  { carry: true, tail: Carry extends true ? 1 : 0 }
    : `${A}${B}` extends `10` | `01`
      ? { carry: Carry, tail: Carry extends true ? 0 : 1 }
      : { carry: false, tail: Carry extends true ? 1 : 0 }

type BinaryAdd<A extends Bit[], B extends Bit[], Carry extends boolean = false, Res extends Bit[] = []> =
  A extends [ ...infer RestA extends Bit[], infer FA extends Bit ]
    ? B extends [ ...infer RestB extends Bit[], infer FB extends Bit ]
      ? Single<FA, FB, Carry> extends infer F
        ? F extends { carry: boolean, tail: Bit }
          ? BinaryAdd<RestA, RestB, F['carry'], [F['tail'], ...Res]>
          : never
        :never
      : never
    : [ ...(Carry extends true ? [1] : []), ...Res ]

Solution by lvjiaxuan #32943

type Bit = 1 | 0
//    { 00 = 0
// 0  { 01 = 1
//    { 11 = 0 +1
//
//    { 00 = 1
// 1+ { 01 = 0 +1
//    { 11 = 1 +1
type AddPattern<A extends Bit, B extends Bit, _Carry extends Bit = 0> = //[Result, NextCarry]
  [A & B] extends [never] ? [_Carry extends 1 ? 0 : 1, _Carry extends 1 ? 1 : 0] :  //01
  [_Carry extends 1 ? 1 : 0, A extends 1 ? 1 : 0];  //00 | 11
  
type BinaryAdd<A extends Bit[], B extends Bit[], _Carry extends Bit = 0> =
  A extends [...infer RA extends Bit[], infer LA extends Bit] ?
  B extends [...infer RB extends Bit[], infer LB extends Bit] ?
  AddPattern<LA, LB, _Carry> extends [infer Result, infer NextCarry extends Bit] ? [...BinaryAdd<RA, RB, NextCarry>, Result] : never :
  never :
  _Carry extends 1 ? [1] : [];  //pop

Solution by E-uler #32792

type Bit = 1 | 0

type BinaryAdd<A extends Bit[], B extends Bit[], _Carry extends Bit = 0> =
  A['length'] extends 0
    ? _Carry extends 1 ? [1] : []
    : [A, B] extends [[...infer RestA extends Bit[], infer LastA extends Bit], [...infer RestB extends Bit[], infer LastB extends Bit]]
      ? [...BinaryAdd<RestA, RestB, Carry<[LastA, LastB, _Carry]>>, XOr<_Carry, XOr<LastA, LastB>>]
      : never

type XOr<A extends Bit, B extends Bit> = A extends B ? 0 : 1
type Carry<T extends Bit[]> = Reject<T, 0>['length'] extends 0 | 1 ? 0 : 1
type Reject<T extends any[], K> = T extends [infer Head, ...infer Rest]
  ? Head extends K ? Reject<Rest, K> : [Head, ...Reject<Rest, K>]
  : []

Solution by Sun79 #32750