Psyche
Psyche

Reputation: 8773

How to make number_format() not to round numbers up

I have this number:

$double = '21.188624';

After using number_format($double, 2, ',', ' ') I get:

21,19

But what I want is:

21,18

Any ideea how can I make this work?

Thank you.

Upvotes: 40

Views: 87427

Answers (19)

Lukas Pierce
Lukas Pierce

Reputation: 1259

Modern PHP has a built-in NumberFormatter class that supports various types of rounding. In your case you need ROUND_DOWN mode

You can create your own formatter and set the desired rounding mode for it:

$fmt = new NumberFormatter('ru_RU', NumberFormatter::DECIMAL);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$fmt->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_DOWN);

echo $fmt->format(21.188624); // 21,18

Upvotes: 0

Derlis Gonzalez
Derlis Gonzalez

Reputation: 1

thanks for your help Dima!!! My function

    private function number_format(float $num, int $decimals = 0, ?string $decimal_separator = ',', ?string $thousands_separator = '.'){
     /**
      * Formatea un numero como number_format sin redondear hacia arriba, trunca el resultado
     * @access private
     * @param string num - Numero de va a ser formateado
     * @param int decimals - Posiciones Decimales
     * @param string|null $decimal_separator — [opcional]
     * @param string|null $thousands_separator — [opcional]
     * @return string — Version de numero formateado.
     */

     $negation = ($num < 0) ? (-1) : 1;
     $coefficient = 10 ** $decimals;
     $number = $negation * floor((string)(abs($num) * $coefficient)) / $coefficient;
     return number_format($number, $decimals, $decimal_separator, $thousands_separator);
}

for use it

echo $this->number_format(24996.46783, 3, ',', '.'); //24.996,467

Upvotes: 0

Jeff Lawrence Tayco
Jeff Lawrence Tayco

Reputation: 1

    $number = 2.278;
    echo new_number_format($number,1);
    //result: 2.2

    function new_number_format($number,$decimal)
    {
        //explode the number with the delimiter of dot(.) and get the whole number in index 0 and the decimal in index 1
        $num = explode('.',$number);
        //if the decimal is equal to zero
        //take note that we can't split the zero value only and it will return Undefined offset if we split the zero only
        //for example: rating_format(2.0,1); the result will be 2. the zero is gone because of the Undefined offset
        //the solution of this problem is this condition below
        if($num[1] == 0)
        {
          $final_decimal = '';
          $i=0;
          //loop the decimal so that we can display depend on how many decimal that you want to display
          while($i<$decimal){
            $final_decimal .= 0;
            $i++;
          }
        }
        //if the decimal is not zero
        else
        {
          $dec = str_split($num[1]); //split the decimal and get the value using the array index
          $i=0;
          $final_decimal = '';
          //loop the decimal so that we can display depend on how many decimal that you want to display
          while($i<$decimal){
            $final_decimal .= $dec[$i];
            $i++;
            }
        }
          $new_number= $num[0].'.'.$final_decimal;//combine the result with final decimal
          return $new_number; //return the final output
    }

Upvotes: 0

Sourav Dutt
Sourav Dutt

Reputation: 72

In case you need 2 fixed decimal places, you can try this!

@Dima's solution is working for me, but it prints "19.90" as "19.9" so I made some changes as follows:

<?php 
function numberPrecision($number, $decimals = 0)
    {
        $negation = ($number < 0) ? (-1) : 1;
        $coefficient = 10 ** $decimals;
        $result = $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
        $arr = explode(".", $result);
        $num = $arr[0];
        if(empty($arr[1]))
            $num .= ".00";
        else if(strlen($arr[1]) == 1)
            $num .= "." . $arr[1] . "0";
        else
            $num .= ".". $arr[1];
        return $num;
    }
    echo numberPrecision(19.90,2); // 19.90

So, what I did is, I just break the result into two parts with explode function. and convert the result into a string with concatenation!

Upvotes: 1

Dima
Dima

Reputation: 319

Function (only precision):

function numberPrecision($number, $decimals = 0)
{
    $negation = ($number < 0) ? (-1) : 1;
    $coefficient = 10 ** $decimals;
    return $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
}

Examples:

numberPrecision(2557.9999, 2);     // returns 2557.99
numberPrecision(2557.9999, 10);    // returns 2557.9999
numberPrecision(2557.9999, 0);     // returns 2557
numberPrecision(2557.9999, -2);    // returns 2500
numberPrecision(2557.9999, -10);   // returns 0
numberPrecision(-2557.9999, 2);    // returns -2557.99
numberPrecision(-2557.9999, 10);   // returns -2557.9999
numberPrecision(-2557.9999, 0);    // returns -2557
numberPrecision(-2557.9999, -2);   // returns -2500
numberPrecision(-2557.9999, -10);  // returns 0

Function (full functionality):

function numberFormat($number, $decimals = 0, $decPoint = '.' , $thousandsSep = ',')
{
    $negation = ($number < 0) ? (-1) : 1;
    $coefficient = 10 ** $decimals;
    $number = $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
    return number_format($number, $decimals, $decPoint, $thousandsSep);
}

Examples:

numberFormat(2557.9999, 2, ',', ' ');     // returns 2 557,99
numberFormat(2557.9999, 10, ',', ' ');    // returns 2 557,9999000000
numberFormat(2557.9999, 0, ',', ' ');     // returns 2 557
numberFormat(2557.9999, -2, ',', ' ');    // returns 2 500
numberFormat(2557.9999, -10, ',', ' ');   // returns 0
numberFormat(-2557.9999, 2, ',', ' ');    // returns -2 557,99
numberFormat(-2557.9999, 10, ',', ' ');   // returns -2 557,9999000000
numberFormat(-2557.9999, 0, ',', ' ');    // returns -2 557
numberFormat(-2557.9999, -2, ',', ' ');   // returns -2 500
numberFormat(-2557.9999, -10, ',', ' ');  // returns 0

Upvotes: 17

mean.cj
mean.cj

Reputation: 123

Javascript Version

function numberFormat($number, $decimals = 0, $decPoint = '.' , $thousandsSep = ',')
{
    return number_format((Math.floor($number * 100) / 100).toFixed($decimals), $decimals, $decPoint, $thousandsSep );
}
 // https://locutus.io/php/strings/number_format/
function number_format(number, decimals, decPoint, thousandsSep) {
    if(decimals === 'undefined') decimals = 2;

    number = (number + '').replace(/[^0-9+\-Ee.]/g, '')
  const n = !isFinite(+number) ? 0 : +number
  const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
  const sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep
  const dec = (typeof decPoint === 'undefined') ? '.' : decPoint
  let s = ''
  const toFixedFix = function (n, prec) {
    if (('' + n).indexOf('e') === -1) {
      return +(Math.round(n + 'e+' + prec) + 'e-' + prec)
    } else {
      const arr = ('' + n).split('e')
      let sig = ''
      if (+arr[1] + prec > 0) {
        sig = '+'
      }
      return (+(Math.round(+arr[0] + 'e' + sig + (+arr[1] + prec)) + 'e-' + prec)).toFixed(prec)
    }
  }
  // @todo: for IE parseFloat(0.55).toFixed(0) = 0;
  s = (prec ? toFixedFix(n, prec).toString() : '' + Math.round(n)).split('.')
  if (s[0].length > 3) {
    s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep)
  }
  if ((s[1] || '').length < prec) {
    s[1] = s[1] || ''
    s[1] += new Array(prec - s[1].length + 1).join('0')
  }
  return s.join(dec)
}

Upvotes: 0

ustmaestro
ustmaestro

Reputation: 1283

I know that this an old question, but it still actual :) .

How about this function?

function numberFormatPrecision($number, $precision = 2, $separator = '.')
{
    $numberParts = explode($separator, $number);
    $response = $numberParts[0];
    if (count($numberParts)>1 && $precision > 0) {
        $response .= $separator;
        $response .= substr($numberParts[1], 0, $precision);
    }
    return $response;
}

Usage:

// numbers test
numberFormatPrecision(19, 2, '.'); // expected 19 return 19
numberFormatPrecision(19.1, 2, '.'); //expected 19.1 return 19.1
numberFormatPrecision(19.123456, 2, '.'); //expected 19.12 return 19.12
numberFormatPrecision(19.123456, 0, '.'); //expected 19 return 19

// negative numbers test
numberFormatPrecision(-19, 2, '.'); // expected -19 return -19
numberFormatPrecision(-19.1, 2, '.'); //expected -19.1 return -19.1
numberFormatPrecision(-19.123456, 2, '.'); //expected -19.12 return -19.12
numberFormatPrecision(-19.123456, 0, '.'); //expected -19 return -19

// precision test
numberFormatPrecision(-19.123456, 4, '.'); //expected -19.1234 return -19.1234

// separator test
numberFormatPrecision('-19,123456', 3, ','); //expected -19,123 return -19,123  -- comma separator

Upvotes: 21

T30
T30

Reputation: 12222

I use this function:

function cutNum($num, $precision = 2) {
    return floor($num) . substr(str_replace(floor($num), '', $num), 0, $precision + 1);
}

Usage examples:

cutNum(5)          //returns 5 
cutNum(5.6789)     //returns 5.67 (default precision is two decimals)
cutNum(5.6789, 3)  //returns 5.678
cutNum(5.6789, 10) //returns 5.6789
cutNum(5.6789, 0)  //returns 5. (!don't use with zero as second argument: use floor instead!)

Explanation: here you have the same function, just more verbose to help understanding its behaviour:

function cutNum($num, $precision = 2) {
    $integerPart = floor($num);
    $decimalPart = str_replace($integerPart, '', $num);
    $trimmedDecimal = substr($decimalPart, 0, $precision + 1);
    return $integerPart . $trimmedDecimal;
}

Upvotes: 5

Bill Stephen
Bill Stephen

Reputation: 99

$double = '21.188624';

$teX = explode('.', $double);

if(isset($teX[1])){
    $de = substr($teX[1], 0, 2);
    $final = $teX[0].'.'.$de;
    $final = (float) $final;
}else{
    $final = $double;   
}

final will be 21.18

Upvotes: 1

quinlan
quinlan

Reputation: 122

The faster way as exploding(building arrays) is to do it with string commands like this:

$number = ABC.EDFG;
$precision = substr($number, strpos($number, '.'), 3); // 3 because . plus 2 precision  
$new_number = substr($number, 0, strpos($number, '.')).$precision;

The result ist ABC.ED in this case because of 2 precision If you want more precision just change the 3 to 4 or X to have X-1 precision

Cheers

Upvotes: 0

Mayank Majithia
Mayank Majithia

Reputation: 1966

In Case you have small float values you can use number_format function this way.

$number = 21.23;

echo number_format($number, 2, '.', ',') ); // 21.23

In case you have you have long decimal number then also it will format number this way

$number = 201541.23;

echo number_format($number, 2, '.', ',') ); // 201,541.23

Upvotes: -1

Etienne Martin
Etienne Martin

Reputation: 11579

Use the PHP native function bcdiv.

function numberFormat($number, $decimals = 2, $sep = ".", $k = ","){
    $number = bcdiv($number, 1, $decimals); // Truncate decimals without rounding
    return number_format($number, $decimals, $sep, $k); // Format the number
}

See this answer for more details.

Upvotes: 4

Abhishek Sharma
Abhishek Sharma

Reputation: 300

 **Number without round**        

   $double = '21.188624';
   echo intval($double).'.'.substr(end(explode('.',$double)),0,2);

**Output** 21.18

Upvotes: 2

kasimir
kasimir

Reputation: 1554

In case you don't care for what comes behind the decimal point, you can cast the float as an int to avoid rounding:

$float = 2.8;
echo (int) $float; // outputs '2'

Upvotes: 0

Asaf Maoz
Asaf Maoz

Reputation: 675

$finalCommishParts = explode('.',$commission);
$commisshSuffix = (isset($finalCommishParts[1])?substr($finalCommishParts[1],0,2):'00');
$finalCommish = $finalCommishParts[0].'.'.$commisshSuffix;

Upvotes: 0

Keith Yeoh
Keith Yeoh

Reputation: 730

public function numberFormatPrecision( $number, $separator = '.', $format = 2 ){

    $response = '';
    $brokenNumber = explode( $separator, $number );
    $response = $brokenNumber[0] . $separator;
    $brokenBackNumber = str_split($brokenNumber[1]);

    if( $format < count($brokenBackNumber) ){

        for( $i = 1; $i <= $format; $i++ )
            $response .= $brokenBackNumber[$i];
    }

    return $response;
}

Upvotes: 0

rahim asgari
rahim asgari

Reputation: 12437

use this function:

function number_format_unlimited_precision($number,$decimal = '.')
{
   $broken_number = explode($decimal,$number);
   return number_format($broken_number[0]).$decimal.$broken_number[1]);
}

Upvotes: -1

Wrikken
Wrikken

Reputation: 70470

number_format will always do that, your only solution is to feed it something different:

$number = intval(($number*100))/100;

Or:

$number = floor(($number*100))/100;

Upvotes: 39

methodin
methodin

Reputation: 6712

floor($double*100)/100

Upvotes: 7

Related Questions