В статье я прочитал, что деление и умножение числа на степень 2 являются тривиальным процессом. Я искал много интернета для объяснения, но не понял. Может ли кто-нибудь объяснить легкими словами, что это на самом деле означает сказать.деление и умножение по мощности 2
ответ
Это тривиально с точки зрения операций с битами. Умножение на 2 эквивалентно сдвигу влево на 1 бит, деление - сдвиг вправо. так же это то же самое тривиальное умножение и деление на любую степень 2.
int a = 123; // or in binary format: a = 0b01111011;
assert (a * 2) == (a << 1); // 2 = 2^1, (a << 1) = 11110110
assert (a/2) == (a >> 1); // 2 = 2^1, (a >> 1) = 00111101
assert (a * 8) == (a << 3); // 8 = 2^3, (a << 3) = 1111011000
assert (a/8) == (a >> 3); // 8 = 2^3, (a >> 3) = 0000001111
Также отметим, что a*2 = a+a
, и добавление иногда даже дешевле, чем меняется, в зависимости от оборудования.
Для подписанного деления обратите внимание на то, что на некоторых языках (например, C) целочисленное деление усекается к нулю, тогда как арифметический сдвиг вправо (сдвиг в копиях знакового бита для дополнения 2) всегда округляется к -Infinity. например (-5)/2 == -2
, но (-5) >> 1 == -3
. Реализация подписанного деления на 2 может выполняться со сдвигом + дополнительные операции, чтобы добавить бит знака, чтобы получить поведение усечения. (Посмотрите на вывод компилятора C.)
В основном умножать и делить числа на степень 2, если число выражается в двоичной системе, нужно просто перевести все двоичный разряд влево или вправо:
00100, что является 4, если вы хотите умножить на 2 * 2 * 2 вы просто перевести все количество осталось 3 раза:
100000, что является exaqctly 32 (4 * 8 = 32)
к разделим это наоборот
с все числа хранятся в двоичном умножении ation/division - операция простого битового сдвига.
Например (умножение):
- 5 = 101 (двоичный)
- 5 * 2 = 10 = 1010 (двоичный) - просто сдвинуты все биты 1 позицию влево
- 5 * 4 = 20 = 10100 (двоичный) - только сдвинутые все биты 2 позиции влево
То же самое относится к делению (операция правого битового сдвига), но вам необходимо рассмотреть перенос для деления нечетных чисел, если вам нужен остаток.
Важно в этом контексте то, что деление на 2 (или на мощность 2) тривиально только для целочисленной арифметики. Это становится менее тривиальным, когда вы говорите о делении с плавающей запятой.
Причина этого заключается в том, что деление на базовое число некоторой системы цифр (двоичный, восьмеричный, шестнадцатеричный, вы называете его) всегда может быть выполнено простым сдвигом вправо числа.
Например, в десятичной системе с разделением по десять у вас есть:
230.0/10.0 = 23.00
(сдвинуть десятичную точку на одну позицию влево, который переводит на сдвиг вправо числа)
же для шестнадцатеричных чисел:
0xA2FF/0x10 = 0xA2F
(номер сдвигается на одну позицию вправо)
И то же самое для двоичных чисел:
1101011/10 = 110101 (binary notation)
107 /2 = 53 (decimal notation for the same equation)
Если вы хотите разделить на степень двойки, число правых сдвигов, которые необходимо выполнить, соответствует показателю. Например, деление на 4 означает деление на 2 * 2, равное двум операциям с правом сдвига:
1101011/100 = 11010 (binary notation, two shift operations)
107 / 4 = 26 (decimal notation)
Бинарные форматы с плавающей запятой (такие как [IEEE754 binary64 aka 'double'] (https://en.wikipedia.org/wiki/Double-precision_floating-point_format)) могут дешево размножаться или делить по степеням 2, просто добавляя или вычитая из поля экспоненты! (Тем не менее, вы должны проверить переполнение). Аппаратное обеспечение не всегда обеспечивает это как отдельную операцию, поэтому часто вы просто умножаете ее на '0,5' с помощью обычной инструкции. AVX512F делает это с помощью '' vscalefsd' (масштаб скалярного двойника на '2^floor (x)')] (https://hjlebbink.github.io/x86doc/html/VSCALEFSD.html) и связанных версий с плавающей точкой и SIMD –
Наверное, это то, что вы подразумевали под * менее * тривиальным, а не * не * тривиальным, но для HW довольно сложно реализовать. –
- 1. C умножение и деление
- 2. Сравните умножение и деление
- 3. Деление и умножение математических ошибок
- 4. Неявно развернутое умножение и деление
- 5. Двумерный массив (умножение/деление)
- 6. Умножение и деление: странный вывод в c
- 7. MySQL Запрос на умножение, добавление и деление
- 8. Java BigInteger факторизация: деление и умножение отличаются
- 9. сложное умножение/деление с бесконечностью и nan
- 10. инкрементируйте петлю по мощности 2
- 11. Умножение и деление, дающее неожиданный результат
- 12. Поточечная умножение и деление правой матрицы
- 13. 8086 умножение/деление дробных чисел
- 14. Целочисленное деление или умножение поплавка?
- 15. Неправильное умножение/деление в поле Галуа (2^8)
- 16. Умножение матрицы по той же мощности с использованием Java
- 17. сложение, вычитание, деление, умножение десятичных дробей
- 18. Перемещает бит быстрее, чем умножение и деление на Java? .СЕТЬ?
- 19. Будет ли компилятор оптимизировать деление на умножение
- 20. Разделите по мощности 2, получив поплавок
- 21. Android Basic Calculator, сложение, вычитание, умножение, деление
- 22. Java двойной точности с постоянным Умножение/Деление
- 23. Как выполнить умножение и деление «сверхдлинных» целых чисел?
- 24. Должен ли я использовать умножение или деление?
- 25. Умножение и деление без операторов в C 4byte float ieee754
- 26. Почему деление более дорогое, чем умножение?
- 27. Полином точность оценки, умножение против деление
- 28. x86 сборка Какие регистры участвуют в умножение и деление
- 29. Python: деление и умножение типа timedelta64 с поплавками
- 30. Умножение и добавить 2 массивы
Это то же самое, что разделение и умножение на 10 для людей. Как вы можете умножить любое число на 10? Просто добавьте ноль. – usr2564301
Будьте осторожны: как только вы попытаетесь отслеживать переполнение при умножении или остаток при делении, это может быть не так тривиально, как вы надеялись. –