Округление до ближайших конечных цифр

У меня есть следующая функция, которая округляет число до ближайшего числа, заканчивающегося цифрами $nearest, и мне было интересно, есть ли более элегантный способ сделать то же самое .

/**
 * Rounds the number to the nearest digit(s).
 *
 * @param int $number
 * @param int $nearest
 * @return int
 */

function roundNearest($number, $nearest, $type = null)
{
    $result = abs(intval($number));
    $nearest = abs(intval($nearest));

    if ($result <= $nearest)
    {
        $result = $nearest;
    }

    else
    {
        $ceil = $nearest - substr($result, strlen($result) - strlen($nearest));
        $floor = $nearest - substr($result, strlen($result) - strlen($nearest)) - pow(10, strlen($nearest));

        switch ($type)
        {
            case 'ceil':
                $result += $ceil;
            break;

            case 'floor':
                $result += $floor;
            break;

            default:
                $result += (abs($ceil) <= abs($floor)) ? $ceil : $floor;
            break;
        }
    }

    if ($number < 0)
    {
        $result *= -1;
    }

    return $result;
}

Некоторые примеры:

roundNearest(86, 9); // 89
roundNearest(97, 9); // 99
roundNearest(97, 9, 'floor'); // 89

Заранее спасибо!

PS: этот вопрос не касается округления до ближайшего кратного.


person Alix Axel    schedule 12.10.2009    source источник
comment
зачем изобретаешь велосипед?   -  person markus    schedule 12.10.2009


Ответы (2)


Это работает для меня:

function roundToDigits($num, $suffix, $type = 'round') {
    $pow = pow(10, floor(log($suffix, 10) + 1));
    return $type(($num - $suffix) / $pow) * $pow + $suffix; 
};

$type должно быть либо "потолок", либо "пол", либо "круглый"

person nickf    schedule 06.01.2010
comment
Всегда округляет числа вниз, возвращает 79, 89 и 89 для примеров, приведенных в моем вопросе. - person Alix Axel; 08.01.2010
comment
Вы изменили параметр $type? roundToDigits(94,9,'floor')==89, roundToDigits(94,9,'ceil')==99, roundToDigits(94,9,'round')==99 - person nickf; 08.01.2010
comment
Упс, нет, я этого не делал! : O Отличное решение, я бы просто изменил $pow = pow(10, floor(log($suffix, 10) + 1));, чтобы он также обрабатывал десятичные дроби. Спасибо! - person Alix Axel; 12.04.2012
comment
Мне только что пришло в голову, как бы вы справились с $suffix = 0? - person Alix Axel; 12.04.2012

Я думаю, что это должно работать, и, по крайней мере, для меня это более элегантно:

function roundNearest($number, $nearest, $type = null)
{
  if($number < 0)
    return -roundNearest(-$number, $nearest, $type);

  $nearest = abs($nearest);
  if($number < $nearest)
    return $nearest;

  $len = strlen($nearest);
  $pow = pow(10, $len);
  $diff = $pow - $nearest;

  if($type == 'ciel')
    $adj = 0.5;
  else if($type == 'floor')
    $adj = -0.5;
  else
    $adj = 0;

  return round(($number + $diff)/$pow + $adj)*$pow - $diff;
}

Изменить: добавлено то, что, думаю, вы хотите от отрицательных входных данных.

person Kip    schedule 12.10.2009
comment
Слишком много повторений, чтобы быть элегантным. - person slikts; 12.10.2009
comment
@Reinis I.: Хорошо, я сделал это немного элегантнее. - person Kip; 13.10.2009