Получаю число делением. Если четное — подходит, если нечетное — нужно изменить на четное, отняв единицу. Подскажите алгоритм решения.
$perPage = 18 / 2; //18 это просто пример, делить нужно и другие числа
echo $perPage; // дает 9, а требуется 8
VladD
206k27 золотых знаков289 серебряных знаков521 бронзовый знак
задан 6 авг 2015 в 14:06
5
Например так:
$perPage = 18 / 2; // может быть и (19 / 2)
echo (floor($perPage / 2) * 2); // выведет 8
ответ дан 6 авг 2015 в 14:10
Dmitriy SimushevDmitriy Simushev
17.7k5 золотых знаков47 серебряных знаков85 бронзовых знаков
6
Еще вариант:
<?php
$perPage = 18 / 2;
echo intval($perPage / 2) * 2;
UPD сделан после принятия ответа как правильный. В ответ на обсуждение в ответе от @Nick Volynkin.
Провел тестирование скорости работы того или иного варианта в такой конструкции:
$start = microtime(TRUE);
for ($i = 2; $i < 100000; $i++) {
// код примера
}
echo "time: ", microtime(TRUE) - $start, "n";
- Ответ от @Dmitriy Simushev, время выполнения ~ 0.60 сек. Ответ от @Nick Volynkin имеет примерно такое же время (т.е. там где заменили двойное деление на 2 на одинарное но на 4).
- Мой ответ, представленный выше, время выполнения ~ 0.54 сек.
- Ответ от @xaja, время выполнения ~ 0.10 сек. Смотрите UPD3.
-
И наконец победитель
Спасибо @VladD’у за напоминание об этом способе:
<?php $perPage = 18 / 2; echo (int)($perPage / 2) * 2;
Время выполнения ~ 0.08 сек.
UPD2 По поводу правильности решения:
-
Если автор работает только с положительными числами, то все ответы перечисленные в UPD дают верный результат;
-
Если на входе есть как положительные числа, так и отрицательные и получить всегда надо ближайшее четное, меньшее или равное данному, то единственный правильный ответ — это ответ от @xaja; Смотрите UPD3.
-
Если же надо получить ближайшее четное по модулю, то правильными ответами являются все кроме ответа от @xaja.
UPD3 Ответ от @xaja в таком виде
$perPage = 18 / 2;
$odd = ($perPage % 2 != 0);
if ($odd) {
$perPage--;
}
echo $perPage;
выдает ошибочный результат для нечетного числа на входе.
ответ дан 6 авг 2015 в 14:12
VismanVisman
16.5k8 золотых знаков25 серебряных знаков56 бронзовых знаков
13
$perPage = 18 / 2;
$odd = ($perPage % 2 != 0);
if ($odd) {
$perPage--;
}
echo $perPage;
ответ дан 6 авг 2015 в 14:11
xajaxaja
2,9693 золотых знака15 серебряных знаков30 бронзовых знаков
2
Как найти ближайшее четное число, меньше или равное данному?
На операциях деления и умножения на степени двойки наиболее эффективен побитный сдвиг (arithmetic shift). (спасибо @BOPOH за код)
-
Сдвиг влево на
nэквивалентен умножению на2na = $x << 2; b = $x * 4; echo (a == b) //true -
Сдвиг вправо на
nэквивалентен делению на2na = $x >> 2; b = $x / 4; echo (a == b) //true
Если отбросить то, что переменная сначала еще раз делилась на два и отвечать на общий вопрос, то достаточно сдвиг вправо и влево на 1 бит:
even = $number >> 1 << 1;
Поскольку в конкретном примере переменная предварительно делилась на два, то мы можем сделать упрощение. Зачем дважды делить на 2, если можно один раз делить на 4?
perPage = $page >> 2 << 1;
Если без сдвига, то можно обойтись простой арифметикой.
perPage = floor($X / 4) * 2;
ответ дан 6 авг 2015 в 22:20
Nick Volynkin♦Nick Volynkin
33.5k24 золотых знака128 серебряных знаков215 бронзовых знаков
9
Если число в целочисленном формате и реализовано допкодом, то надо почистить младший двоичный разряд. Это делает операция
$x & -2
ответ дан 19 ноя 2015 в 20:03
Ну раз деление не нужно, можно двумя сдвигами:
$a = $a >> 1
$a = $a << 1
Если предположить что максимальное целое в PHP — 0xFFFFFFFF, то можно вообще одной операцией младший бит сбросить:
$a = $a & 0xFFFFFFFE
ответ дан 7 авг 2015 в 8:38
Владимир МартьяновВладимир Мартьянов
9,6394 золотых знака21 серебряный знак35 бронзовых знаков
5
Округление до четного числа вниз — это очистка младшего двоичного разряда:
$x & ~1
Округление до четного числа вверх — это добавление 1 и очистка младшего разряда:
($x + 1) & ~1
ответ дан 7 авг 2015 в 15:00
AbyxAbyx
30.8k13 золотых знаков96 серебряных знаков155 бронзовых знаков
3
<?php
$a=18;
if($a % 2 == 0){
$c = ($a / 2) - 1;
}else{
$c = $a / 2;
}
echo $c;
?>
ответ дан 6 авг 2015 в 14:30
4
So how to create a function to return nearest up so nearest to 9 9+ 1 to given int leaving no remainder when divided by 2 int?
Greg Hewgill
941k181 gold badges1139 silver badges1280 bronze badges
asked Dec 5, 2010 at 18:13
5
To round to the nearest int:
number+=(number & 1)
answered Dec 5, 2010 at 18:18
SeanSean
60.6k11 gold badges96 silver badges134 bronze badges
5
Round down to even
x & ~1
Round up to even
(x + 1) & ~1
answered Dec 5, 2010 at 18:19
AbyxAbyx
12.2k5 gold badges44 silver badges76 bronze badges
3
«Nearest» is ambiguous when given an integer. Take, say, 9: both 8 and 10 are even, and are equally near to it. If you want to always go up, then something like…
int nearestEvenInt(int to)
{
return (to % 2 == 0) ? to : (to + 1);
}
answered Dec 5, 2010 at 18:16
Adam WrightAdam Wright
48.9k12 gold badges130 silver badges152 bronze badges
2
number % 2 == 0?number:number+1
Another way is (number>>1)<<1 but I’m not sure about negatives/little/big-endians.
answered Dec 5, 2010 at 18:16
khachikkhachik
27.9k9 gold badges59 silver badges92 bronze badges
1
The way I’d normally prefer is (number+1) & ~1, but not everyone recognises the idiom, so you might have to consider your audience.
In particular, if it’s supposed to work for negative integers then non-two’s-complement implementations of C and C++ don’t recognise the idiom (it’ll round odd negative numbers down instead of up on negative sign+magnitude numbers, and turn negative even numbers odd on ones’ complement), so it’s not entirely portable in the case where negative input is allowed.
The portable answer is (number % 2 == 0) ? number : number+1;, and let the compiler worry about optimization.
Beware also that you haven’t defined what the result should be for INT_MAX, which is odd but for which there does not exist a larger even int value.
answered Dec 5, 2010 at 18:41
Steve JessopSteve Jessop
272k39 gold badges455 silver badges697 bronze badges
2
if (x %2 == 0) return x; else return x+1; ?
answered Dec 5, 2010 at 18:16
davkadavka
13.9k11 gold badges60 silver badges86 bronze badges
Since most of the answers here are either nonportable or have excess conditionals, here is the fast and portable answer:
number += (int)((unsigned)number & 1)
The case to unsigned ensures that bitwise-and is defined as expected, and the cast back to int (which is well-defined because both possible values of the bitwise and operation, zero or one, fit in int) prevents number from getting promoted to unsigned, which would then result in implementation-defined behavior when it’s converted back to int to assign the result to number.
answered Dec 6, 2010 at 5:46
A little late to the party, but this is a clean solution
n += (n % 2);
answered Apr 5, 2017 at 20:16
I know the OP asked for int, but here’s one answer for floats too:
number = Math.round(number * 0.5f) * 2; //Closest (up for middle)
number = Math.ceil(number * 0.5f) * 2; //Always Up
number = Math.floor(number * 0.5f) * 2; //Always Down
answered Apr 6, 2014 at 12:49
Обычно я предпочитаю (number+1) & ~1, но не каждый признает идиому, поэтому вам, возможно, придется подумать о своей аудитории.
В частности, если он должен работать для отрицательных целых чисел, то реализация не-двух-дополнений C и С++ не распознает идиому (она будет округлять нечетные отрицательные числа вниз, а не вверх по отрицательным знакам + номерам величин, и превращать отрицательные четные числа нечетными в их дополнение), поэтому он не полностью переносится в случае, когда разрешен отрицательный вход.
Портативный ответ (number % 2 == 0) ? number : number+1;, и пусть компилятор беспокоится об оптимизации.
Остерегайтесь также того, что вы не определили, какой результат должен быть для INT_MAX, который является нечетным, но для которого не существует большего значения int.
Можно рассуждать так. Чтобы найти ближайшее к 439 четное число нужно
1)старший разряд (сотни) оставить без изменений;
2)второй разряд (десятки) увеличить на минимально возможное число (оставить его без изменений или уменьшить нельзя, потому что при этом не получится больше, чем 439). Пробуем увеличить на 1, получается 4. Не годится, т.к. такая цифра уже есть в разряде сотен. Увеличим ещё на 1, получается 5. Годится.
3)в младшем разряде (единиц) написать минимальную из возможных четных цифр. Это 0.
Итого, получится число 450.
Я бы предпочел, чтобы (number+1) & ~1, но не все признают идиому, поэтому вам, возможно, придется рассмотреть свою аудиторию.
В частности, если предполагается, что он работает для отрицательных целых чисел, то реализации C-и C++, отличные от двух, не распознают эту идиому (она округляет нечетные отрицательные числа вместо отрицательных знаков + чисел и превращается в отрицательные). четные числа (нечетные по своему дополнению), поэтому он не является полностью переносимым в случае, когда разрешен отрицательный ввод
Портативный ответ (number % 2 == 0) ? number : number+1;и позвольте компилятору беспокоиться об оптимизации.
Остерегайтесь также, что вы не определили, каким должен быть результат INT_MAX, что странно, но для которого не существует более четного int значение.

Спасибо @VladD’у за напоминание об этом способе: