Удалить цифры после двух десятичных знаков без округления значения

У меня есть значение в переменной PHP, как это

$var='2.500000550';
echo $var

что я хочу, чтобы удалить все десятичные точки после 2 цифр.

как сейчас значение переменной будет

$var='2.50';
echo $var

имейте в виду, что это значение исходит из базы данных MySQL

но когда я использую round php function я получил раунд, но мне не нужен раунд, мне просто нужно удалить все цифры после 2 десятичных простых.

я устал, flot() и много других вариантов безуспешно.

Спасибо

13 ответов

Решение

TL;DR:

Нативная функция PHP bcdiv, кажется, делает именно то, что требуется, и правильно.

Чтобы просто "усечь" число, bcdiv($var, 1, 2); где 2 - количество сохраняемых десятичных знаков (а 1 - деноменатор - деление числа на 1 позволяет просто усечь исходное число до желаемых десятичных знаков)

Полный ответ (для истории)

Это оказывается более неуловимым, чем можно подумать.

После того, как этот ответ был (неверно) отозван совсем немного, до меня дошло, что даже sprintf будет округляться.

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

number_format - неверно. (раунды)
Попробуйте использовать числовой формат:

$var = number_format($var, 2, '.', '');  // Last two parameters are optional
echo $var;
// Outputs 2.50

Если вы хотите, чтобы это был номер, просто приведите тип к float:

$var = (float)number_format($var, 2, '.', '');

Примечание: как уже отмечалось в комментариях, это фактически округляет число.

sprintf - неверно. (Спринтф также раунды)
Если важно не округлять число, то ответьте ниже, используйте sprintf:

$var = sprintf("%01.2f", $var);

пол - не совсем! (пол округляет отрицательные числа)

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

floor(2.56789 * 100) / 100; // 2.56

Где 100 соответствует точности, которую вы хотите. Если вы хотите, чтобы это было три цифры, то:

floor(2.56789 * 1000) / 1000; // 2.567

Однако это имеет проблему с отрицательными числами. Отрицательные числа по-прежнему округляются, а не усекаются:

floor(-2.56789 * 100) / 100; // -2.57

"Старый" Правильный ответ: функция пола

Таким образом, полностью надежное решение требует функции:

function truncate_number( $number, $precision = 2) {
    // Zero causes issues, and no need to truncate
    if ( 0 == (int)$number ) {
        return $number;
    }
    // Are we negative?
    $negative = $number / abs($number);
    // Cast the number to a positive to solve rounding
    $number = abs($number);
    // Calculate precision number for dividing / multiplying
    $precision = pow(10, $precision);
    // Run the math, re-applying the negative value to ensure returns correctly negative / positive
    return floor( $number * $precision ) / $precision * $negative;
}

Результаты от вышеупомянутой функции:

echo truncate_number(2.56789, 1); // 2.5
echo truncate_number(2.56789);    // 2.56
echo truncate_number(2.56789, 3); // 2.567

echo truncate_number(-2.56789, 1); // -2.5
echo truncate_number(-2.56789);    // -2.56
echo truncate_number(-2.56789, 3); // -2.567

Новый правильный ответ

Используйте нативную функцию PHP bcdiv

echo bcdiv(2.56789, 1, 1);  // 2.5
echo bcdiv(2.56789, 1, 2);  // 2.56
echo bcdiv(2.56789, 1, 3);  // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 2); // -2.56
echo bcdiv(-2.56789, 1, 3); // -2.567
floor(2.500000550 * 100) / 100;

Это должно сделать вашу задачу...

Попробуйте с number_format:

echo number_format('2.50000050', 2); // 2.50

Вы запрашиваете функцию, которая возвращает "2.50" и не 2.5так что вы говорите не об арифметике, а о манипулировании строками. затем preg_replace твой друг:

$truncatedVar = preg_replace('/\.(\d{2}).*/', '.$1', $var);

// "2.500000050" -> "2.50", "2.509" -> "2.50", "-2.509" -> "2.50", "2.5" -> "2.5"

Если вы хотите сделать это с помощью арифметики, просто используйте:

$truncatedVar = round($var * 100) / 100);

// "2.500000050" -> "2.5", "2.599" -> "2.59", "-2.599" -> "2.59"

Число _формат округляет число

php > echo number_format(128.20512820513, 2)."\n";
128.21

Я использовал preg_replace, чтобы действительно вырезать строку

php > echo preg_replace('/(\.\d\d).*/', '$1', 128.20512820513)."\n";
128.20

Используйте встроенную функцию PHP bcdiv.

Пример:

echo bcdiv(3.22871, 1, 1);  // 3.2
echo bcdiv(3.22871, 1, 2);  // 3.22
echo bcdiv(3.22871, 1, 3);  // 3.228
echo bcdiv(-3.22871, 1, 1); // -3.2
echo bcdiv(-3.22871, 1, 2); // -3.22

Для вашего случая:

$var='2.500000550';
echo $var
echo bcdiv($var, 1, 2);  // 2.50

Использовать sprintf

sprintf("%01.2f", $var);

Кто -то написал здесь о

пол (2.500000550 * 100) / 100;

function cutAfterDot($number, $afterDot = 2){
$a = $number * pow(10, $afterDot);
$b = floor($a);
$c = pow(10, $afterDot);
echo "a $a, b $b, c $c<br/>";
return $b/$c ;
}
echo cutAfterDot(2.05,2);

a 205, b 204, c 100
2.04

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

function cutAfterDot($number, $afterDot = 2){
        return floor($number * pow(10, $afterDot) + 0.00001) / pow(10, $afterDot);
    }

оно работает!

Ниже приведено (что я считаю - пожалуйста, поправьте меня, если нет) надежное математическое* решение, основанное главным образом на информации, полученной от нескольких других отвечающих здесь, и небольшого количества от меня

(* Это не значит, что с ответом Липтьера на основе регулярных выражений что-то не так - просто я вижу, как пуристы хотят избежать регулярных выражений для решения математической проблемы.)

  • sprintf(), number_format() (а также round()(очевидно), все они выполняют операцию округления, поэтому они не подходят для усечения без округления, запрошенного в вопросе (по крайней мере, не самостоятельно).
  • Вместо оригинальной функции, казалось бы, самое элегантное решение было ответом Суджита Агарвала
  • Но из-за способа хранения чисел с плавающей точкой нам нужно использовать эпсилон - как указано в ответе Дэвида Константина (где он также делает предыдущее решение более общим, используя pow() чтобы получить правильный коэффициент на основе указанной точности).
  • Но затем, как указано в ответе cale_b, любое использование floor() (или предположительно ceil()) может привести к непредвиденным результатам для негативов без использования abs(),
  • И ценность, которую я пытаюсь добавить:
    • При использовании деления на abs() чтобы получить коэффициент отрицания, нам нужно учесть особый случай, когда входное значение равно 0.
    • Мы должны динамически создавать эпсилон; Статический жестко закодированный эпсилон может быть слишком маленьким или слишком большим, в зависимости от требуемой точности. Я не видел эту проблему в других ответах.

Код, который я использую:

public static function truncate_decimal($number, $leavePlaces = 2)
{
    if ($number == 0) return 0;
    $negate = $number / abs($number);
    $shiftFactor = pow(10, $leavePlaces);
    $epsilon = pow(10, -1 * $leavePlaces);
    return floor(abs($number) * $shiftFactor + $epsilon) / $shiftFactor * $negate;
}

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

function truncate_decimals($number, $decimals=2)
{
  $factor = pow(10,$decimals); 
  $val = intval($number*$factor)/$factor;
  return $val;
}


truncate_decimals(199.9349,2);
// 199.93
$num = 118.74999669307;
$cut = substr($num, 0, ((strpos($num, '.')+1)+2));
// Cut the string from first character to a length of 2 past the decimal.
// substr(cut what, start, ( (find position of decimal)+decimal itself)+spaces after decimal) )
echo $cut; 

Простая функция, которой нужно следовать, будет "Если больше 0 этаж, иначе ceil", используя множитель, чтобы временно поднять его выше десятичной точки при выполнении этого:

function trim_num($num_in, $dec_places = 2) {
    $multiplier = pow(10, $dec_places); // 10, 100, 1000, etc
    if ($num_in > 0) {
        $num_out = floor($num_in * $multiplier) / $multiplier;
    } else {
        $num_out = ceil($num_in * $multiplier) / $multiplier;
    }
    return $num_out;
}

пол - не совсем! (пол округляет отрицательные числа)

Возможное решение из ответа cale_b.

static public function rateFloor($rate, $decimals)
{

    $div = "1" . str_repeat("0", $decimals);

    if ($rate > 0) {
        return floor($rate * $div) / $div;
    }

    $return = floor(abs($rate) * $div) / $div;

    return -($return);

}

static public function rateCeil($rate, $decimals)
{

    $div = "1" . str_repeat("0", $decimals);

    if ($rate > 0) {
        return ceil($rate * $div) / $div;
    }

    $return = ceil(abs($rate) * $div) / $div;

    return -($return);

}

положительный

Оценить: 0.00302471

Этаж: 0.00302400

Ceil: 0,00302500

отрицательный

Рейтинг: -0.00302471

Этаж: -0.00302400

Ceil: -0.00302500

Все решения, которые используют number_format, неверны, потому что number_format выполняет округление.

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

function truncate_decimal($number, $truncate_decimal_length = 2, $decimal_character = '.', $thousands_character = '') {

$number = explode($decimal_character, $number);
$number[1] = substr($number[1], 0, $truncate_decimal_length);
$number_truncated = implode($decimal_character, $number);
return number_format($number_truncated, $truncate_decimal_length, $decimal_character, $thousands_character);

}

Если вы не хотите округлять число, но хотите удалить десятичные разряды, вы можете использовать метод "substr"

substr(string, start, length);
substr(4.96, 0, -1);
Другие вопросы по тегам