Округлить до ближайшего 5 или 9 в PHP

Мне нужно округлить цены на продукты до ближайших 5 или 9 с помощью функции PHP.

Например, всегда нужно округлять:

$243 would round up to $245

$247 would round up to $249

В настоящее время используется следующий код, но округляется только до ближайшего 5:

function round_five($num) {
    return round($num*2,-1)/2;
}

Буду признателен за любой совет ‹3


person Dean    schedule 21.04.2018    source источник
comment
Вероятно, вас проголосовали против, потому что вы забыли показать какой-то код, который вы пробовали.   -  person pokeybit    schedule 21.04.2018
comment
Давай, Дин, вернись, а когда застрянешь, вернись и опубликуй свой код. SO - это не то место, где люди пишут ваш код за вас, но мы будем рады помочь, если вы приложите немного усилий.   -  person billynoah    schedule 21.04.2018
comment
Привет, добро пожаловать в Stack Overflow. Прочтите, пожалуйста, о Как задать хороший вопрос и как предоставить минимальный полный проверяемый пример (MCVE). Ваше здоровье   -  person Martin    schedule 21.04.2018
comment
извините, я здесь новенький, я обновил сообщение   -  person Dean    schedule 21.04.2018
comment
@Devon до до 245   -  person Martin    schedule 21.04.2018
comment
Ах, я пропустил всегда облаву.   -  person Devon    schedule 21.04.2018


Ответы (3)


Это немного нематично, но должно сработать:

function round9($n) {
    $n = ceil($n);
    $r = substr($n,-1) > 5 ? 9 : 5;
    $n = substr($n,0,-1) . $r;
    return $n;
}
  • первое округление до ближайшего целого числа
  • получить последнюю цифру
  • замените последнюю цифру на 9, если она больше 5. В противном случае замените на 5.

ОБНОВЛЕНИЕ: я подумал, что это интересная проблема, и теперь, когда у нас есть три правильных ответа, которые решают ее с самых разных точек зрения, я подумал, что сделаю небольшой анализ производительности для собственного любопытства. Ответ neuro_sys однозначно побеждает! Вот результаты в секундах для выполнения 10 миллионов итераций:

time to build array: 1.7170281410217
round9: 10.753921985626
my_round: 1.6339750289917
rounder: 16.578145980835

Тест проводился на 4-ядерном VPS Linode объемом 8 ГБ под управлением Ubuntu 16.04 / PHP 7.0.14

person billynoah    schedule 21.04.2018
comment
Идеально! забыл упомянуть выше, есть десятичные точки, ваш код также работает с десятичными точками. Спасибо!! - person Dean; 21.04.2018
comment
Нет проблем, Дин - вы указали цены и woocommerce - я подумал, что в цифрах будут задействованы гроши. - person billynoah; 21.04.2018

Проверяя, является ли остаток от деления на 10 меньше 5, мы округляем его до 5, в противном случае, если он больше 5, мы округляем его до 9. Если нет, остаток равен 5, и мы возвращаем само число.

function my_round($number) {
    $inumber = ceil($number);

    $mod_10 = $inumber % 10;
    $mod_5 = $inumber % 5;

    if ($mod_10 < 5) {
        return $inumber + 5 - $mod_5;
    }

    if ($mod_10 > 5) {
        return $inumber + 10 - $mod_10 - 1;
    }

    return $inumber;
}

echo my_round(243) . PHP_EOL;
echo my_round(247) . PHP_EOL;
echo my_round(5) . PHP_EOL;
echo my_round(9) . PHP_EOL;
echo my_round(10) . PHP_EOL;
echo my_round(0) . PHP_EOL;
echo my_round(5.1) . PHP_EOL;
echo my_round(8.9) . PHP_EOL;
echo my_round(9.1) . PHP_EOL;

Выходы:

245
249
5
9
15
5
9
9
15

Требования немного расплывчаты, поэтому его все еще можно настроить, чтобы справиться с другими угловыми случаями.

person neuro_sys    schedule 21.04.2018
comment
@Dean Пожалуйста, я только что отредактировал небольшую ошибку, поэтому убедитесь, что у вас правильная. - person neuro_sys; 21.04.2018
comment
Вы можете объяснить свой ответ. - person Martin; 21.04.2018
comment
При вводе 5 эта функция возвращает 10. - person Matt Gibson; 21.04.2018
comment
@MattGibson Спасибо, что поймали это, я исправил. - person neuro_sys; 21.04.2018
comment
@Martin Я добавил объяснение. - person neuro_sys; 21.04.2018
comment
5.1 достает мне 5.1. не округляется до ближайшего 5 или 9. - person billynoah; 21.04.2018
comment
@billynoah Спасибо, я исправил работу с числами с плавающей запятой. - person neuro_sys; 21.04.2018
comment
ближе, но все равно не работает. в соответствии с его схемой, 5.1 должно стать 9. в вашей функции это становится 5. - person billynoah; 21.04.2018
comment
вот так. изменив отрицательный голос на положительный :-) Ура, вы решили это с помощью математики, которая почему-то кажется лучше, чем мое решение, в основном основанное на строках. Тем не менее, приятно иметь пример другого пути - этот вопрос кажется проще, чем есть на самом деле. - person billynoah; 21.04.2018
comment
@billynoah Ура! - person neuro_sys; 21.04.2018
comment
@neuro_sys - см. мой обновленный ответ выше для анализа производительности, если вам интересно. - person billynoah; 21.04.2018
comment
@billynoah Ха-ха, отлично! Я также люблю часто сравнивать результаты. - person neuro_sys; 21.04.2018

Связанные вопросы, которые вы должны были прочитать:

Это решение:

Поскольку ваша проблема не использует базовую математику (5 и 9 являются произвольными) или большие показатели (наибольшее количество - 5 цифр, 0,1,2,3,4), просто подсчитайте числа:

<?php
function rounder($n) {
    $x=[5,9];
    $zz = ceil($n);
     $b = substr((string)$zz, -1); 
    while( !in_array($b,$x) ){
       
        $zz++;     
        $b = substr((string)$zz, -1);
    }
    
    return $zz;
}

$array[] = 243;
$array[] = 247;
$array[] = 249;
$array[] = 240;
$array[] = 250;

foreach($array as $row){

     print rounder($row)."<Br>";

}
unset($row);

========================

Вывод:

245
249
249
245
255

Это, вероятно, можно сократить до нескольких строк кода ... но как бы то ни было

person Martin    schedule 21.04.2018
comment
Вопрос не связан ни с какими центами - person Martin; 21.04.2018
comment
Центы @billynoah игнорируются. - person Martin; 21.04.2018
comment
235,50 дает мне 235. Все еще неверно, так как оно не округляется. в его вопросе конкретно говорится, что он хочет округлить цены, и цена может быть не целым числом. - person billynoah; 21.04.2018
comment
@billynoah ни один из примеров не содержит центов; цены не всегда центов. Это деталь, которую вы применили; не деталь, требуемая ОП. Во всяком случае. Исправлено с ceil(). - person Martin; 21.04.2018
comment
Я не думаю, что было большой натяжкой предполагать, что некоторые цены могут содержать центы, а когда вы говорите о ценах, вы почти всегда говорите о числах с плавающей запятой и десятичных дробях. в любом случае, я отменил свой голос против. это еще один хороший ответ, использующий еще одну технику. ваше здоровье - person billynoah; 21.04.2018
comment
см. мой обновленный ответ выше для анализа производительности, если вам интересно. - person billynoah; 21.04.2018
comment
@billynoah, спасибо. Первоначально я пометил ваш + 10, потому что он работает и имеет гораздо меньшую кодовую базу, чем моя. tbh вся концепция округления цен до 5 или 9 кажется нестандартной, поэтому я вижу ожидание того, что можно было бы ожидать центов, но изначально этого не было в OP ... - person Martin; 21.04.2018