Штука в том что вообще number - это 64-битовое число с плавающей точкой, но для побитовых операций он приводится к int32. Т.е. целочисленное деление на 2 побитовым сдвигом возможно без потерь только если делимое (его целая часть) влезает в 32 бита. Согласно спекам array.length является uint32, тогда выходит сумма двух индексов массива может выйти за 32 бита. Я бы использовал Math.trunc((low + high) / 2 ), в статье используется Math.floor что для положительного числа даст тот же результат (индексы же - значит положительное), но по-моему это хуже с точки зрения семантики .
Спасибо, это интересно. Один момент, второй пример как будто не удачный, там же нет ничего неожиданного - тип FnObjArg требует чтобы аргумент содержал число n:
type FnObjArg = { n: number };
const arg2 = {m: 2} as const;
const res = fn(arg);
В оригинальном примере в доках тип объявляет все члены как необязательные, но при передаче аргумента с какими-то другими полями возникает ошибка.
Так а разве мемоизировать все что можно имеет смысл? Или компилятор будет судить что дешевле - мемоизация или перевычисление?
Штука в том что вообще number - это 64-битовое число с плавающей точкой, но для побитовых операций он приводится к int32. Т.е. целочисленное деление на 2 побитовым сдвигом возможно без потерь только если делимое (его целая часть) влезает в 32 бита.
Согласно спекам array.length является uint32, тогда выходит сумма двух индексов массива может выйти за 32 бита.
Я бы использовал Math.trunc(
(low + high) / 2 ),
в статье используется Math.floor что для положительного числа даст тот же результат (индексы же - значит положительное), но по-моему это хуже с точки зрения семантики .А разве
low + high
тут в общем случае не могут вылезти за пределы int32?Спасибо, это интересно. Один момент, второй пример как будто не удачный, там же нет ничего неожиданного - тип FnObjArg требует чтобы аргумент содержал число n:
В оригинальном примере в доках тип объявляет все члены как необязательные, но при передаче аргумента с какими-то другими полями возникает ошибка.