Math.floor VS Math.trunc JavaScript

Фон

Я делаю функцию, которая получает положительное число, а затем округляет число до ближайшего целого числа ниже.

Я использовал Math.floor, но недавно я обнаружил Math.trunc.

Я знаю, что оба возвращают одинаковое значение, учитывая положительное число, и что они работают совершенно по-разному. Мне интересно изучить это поведение.

Вопросы

  • Какой из них быстрее?
  • Какой я должен использовать?

Ответ 1

На самом деле, существует гораздо больше альтернативных способов удаления десятичных чисел из числа. Но это компромисс между удобочитаемостью и скоростью.

Выбор правильного зависит от того, что вам нужно. Если вам просто нужно удалить десятичные дроби, всегда используйте trunc() или побитовые операторы.
floor(), ceil() и round() концептуально очень отличаются от trunc().

Математическая библиотека

Вы уже знаете это. Всегда используйте их в стандартном некритическом коде.

var v = 3.14;
[Math.trunc(v), Math.floor(v), Math.ceil(v), Math.round(v)]
// prints results

для разных входных значений вы получаете эти результаты

          t   f   c   r
 3.87 : [ 3,  3,  4,  4]
 3.14 : [ 3,  3,  4,  3]
-3.14 : [-3, -4, -3, -3]
-3.87 : [-3, -4, -3, -4]

Но это веселее :)

Бинарные операции и побитовые операторы

Если вы посмотрите на них в коде, с первого взгляда может быть неясно, что они делают, поэтому не используйте их в обычном коде. Хотя в некоторых случаях они могут быть полезны. Например, вычисление координат в <canvas/>. Они намного быстрее, но идут с ограничениями.

Концептуально они работают так:

  • Операнды преобразуются в 32-разрядные целые числа со знаком и, таким образом, теряют все десятичные дроби. (Числа, содержащие более 32 бит, получают свои самые старшие (самые левые) биты , отбрасываемые - обычно это знаковый бит.)
[
~~0b011100110111110100000000000000110000000000001, // -1610588159 - before
             ~~0b10100000000000000110000000000001, // -1610588159 - after
]

Битовые логические операторы

  • Каждый бит в первом операнде связан с соответствующим битом во втором операнде. (Первый бит в первый бит, второй бит во второй бит и т.д.)
  • Оператор применяется к каждой паре битов, а результат создается поразрядно.

Операции побитового сдвига

  • Эти операторы принимают value для смещения и number битовых позиций для смещения value на.

усечения

Однако при усечении мы всегда используем 0, ноль, a false в качестве второго операнда, который ничего не делает с исходным значением, кроме преобразования в целое число, в следующих случаях:

~ НЕ ~~v

| ИЛИ v | 0

<< Сдвиг влево v << 0

>> Подпись вправо v >> 0

>>> Сдвиг вправо с нулевым заполнением v >>> 0

var v = 3.78;
[ ~~v ,  v | 0 ,  v << 0 ,  v >> 0 ,  v >>> 0 ]
// prints these results

 3.78 : [ 3,  3,  3,  3, 3]
 3.14 : [ 3,  3,  3,  3, 3]
-3.74 : [-3, -3, -3, -3, 4294967293]
-3.14 : [-3, -3, -3, -3, 4294967293]

Производительность

https://jsperf.com/number-truncating-methods/1

enter image description here

Ответ 2

если аргумент является положительным числом, Math.trunc() эквивалентен Math.floor(),  иначе Math.trunc() эквивалентен Math.ceil().

для проверки производительности этот, а самый быстрый - Math.trunc

var t0 = performance.now();
var result = Math.floor(3.5);
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
var t0 = performance.now();
var result = Math.trunc(3.5);
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);

результат Взял 0.0300 миллисекунд, чтобы сгенерировать: 3 Взял 0.0200 миллисекунд, чтобы сгенерировать: 3

поэтому, если аргументы представляют собой только положительные числа, вы можете использовать самый быстрый из них.