127

Given, say, 1.25 - how do I get "1" and ."25" parts of this number?

I need to check if the decimal part is .0, .25, .5, or .75.

alex
  • 479,566
  • 201
  • 878
  • 984
StackOverflowNewbie
  • 39,403
  • 111
  • 277
  • 441
  • Will a simple explode work? $splitDec = explode(".", $decimal); $splitDec[0] will now by the 1 and splitDec[1] will now be 25 from your example. – Matt Jul 08 '11 at 02:35
  • @Matt `split()` has been deprecated. – alex Jul 08 '11 at 02:36
  • @alex yea, forgot. Was thinking javascript. changed to explode. – Matt Jul 08 '11 at 02:37
  • @Matt, split has been deprecated as of PHP 5.3 and actually takes a regex as its arg, whereas explode takes a string. explode() is preferred in this case. – shelhamer Jul 08 '11 at 02:37
  • 4
    Be aware that `explode(".",1.10);` wil give 1 and 1, not 1 and 10 – Michel Oct 08 '13 at 10:29

20 Answers20

221
$n = 1.25;
$whole = floor($n);      // 1
$fraction = $n - $whole; // .25

Then compare against 1/4, 1/2, 3/4, etc.


In cases of negative numbers, use this:

function NumberBreakdown($number, $returnUnsigned = false)
{
  $negative = 1;
  if ($number < 0)
  {
    $negative = -1;
    $number *= -1;
  }

  if ($returnUnsigned){
    return array(
      floor($number),
      ($number - floor($number))
    );
  }

  return array(
    floor($number) * $negative,
    ($number - floor($number)) * $negative
  );
}

The $returnUnsigned stops it from making -1.25 in to -1 & -0.25

seanbreeden
  • 6,104
  • 5
  • 36
  • 45
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
40

This code will split it up for you:

list($whole, $decimal) = explode('.', $your_number);

where $whole is the whole number and $decimal will have the digits after the decimal point.

shelhamer
  • 29,752
  • 2
  • 30
  • 33
  • 16
    Be aware that `explode(".",1.10);` wil give 1 and 1, not 1 and 10 – Michel Oct 08 '13 at 10:29
  • 4
    This breaks and throws warning about undefined index, if number is integer or does not contain decimal part. – Andreyco Nov 16 '13 at 16:42
  • 1
    This assumes that the number is not going to end up being represented in scientific notation when cast to string. If it's a really really huge or really really tiny number then this won't be the case and this method will break. – GordonM Oct 04 '15 at 09:37
  • It doesn't work when your number is : $value = 10000000000000.00011111; – Hamid Naghipour Sep 25 '20 at 13:51
  • this works very well for numbers in outline form (``x.y``) - thanks – cloudxix Jul 14 '22 at 08:42
35

The floor() method doesn't work for negative numbers. This works every time:

$num = 5.7;
$whole = (int) $num;  // 5
$frac  = $num - $whole;  // .7

...also works for negatives (same code, different number):

$num = -5.7;
$whole = (int) $num;  // -5
$frac  = $num - $whole;  // -.7
evilReiko
  • 19,501
  • 24
  • 86
  • 102
thedude
  • 597
  • 5
  • 5
  • when the number is something like $value = 10000000000000.00011111; it does not work too – Hamid Naghipour Sep 25 '20 at 13:55
  • @HamidNaghipour It does as long as your processor can handle enough bits. It's a limitation of the computer handling it as a numeric value instead of a string. – Eric Jun 29 '22 at 20:26
23

Just to be different :)

list($whole, $decimal) = sscanf(1.5, '%d.%d');

CodePad.

As an added benefit, it will only split where both sides consist of digits.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 2
    This one does not break if number does not contain decimal part. Great! – Andreyco Nov 16 '13 at 16:41
  • Nice that this outputs two integers; rather than an int and a float. – The Thirsty Ape Dec 12 '13 at 21:31
  • 1
    This assumes that the number is not going to end up being represented in scientific notation when cast to string. If it's a really really huge or really really tiny number then this won't be the case and this method will break. – GordonM Oct 04 '15 at 09:42
  • And this one dose not work when the number is like this: $value = 10000000000000.00011111; – Hamid Naghipour Sep 25 '20 at 13:52
  • 1
    sscanf() first argument should be a string https://www.php.net/manual/fr/function.sscanf.php don't forget to cast your float to a string – Julien Dec 08 '20 at 14:14
  • `sscanf()` performs greedy matching and variables can be assigned within the function call (`list()` is not required) https://stackoverflow.com/a/69039147/2943403 – mickmackusa Oct 21 '21 at 02:55
17

a short way (use floor and fmod)

$var = "1.25";
$whole = floor($var);     // 1
$decimal = fmod($var, 1); //0.25

then compare $decimal to 0, .25, .5, or .75

mpalencia
  • 5,481
  • 4
  • 45
  • 59
8

Cast it as an int and subtract

$integer = (int)$your_number;
$decimal = $your_number - $integer;

Or just to get the decimal for comparison

$decimal = $your_number - (int)$your_number
Dom
  • 2,980
  • 2
  • 28
  • 41
5

There's a fmod function too, that can be used : fmod($my_var, 1) will return the same result, but sometime with a small round error.

ip512
  • 128
  • 2
  • 9
5

PHP 5.4+

$n = 12.343;
intval($n); // 12
explode('.', number_format($n, 1))[1]; // 3
explode('.', number_format($n, 2))[1]; // 34
explode('.', number_format($n, 3))[1]; // 343
explode('.', number_format($n, 4))[1]; // 3430
Vasil Nikolov
  • 1,112
  • 10
  • 17
5

Just a new simple solution, for those of you who want to get the Integer part and Decimal part splitted as two integer separated values:

5.25 -> Int part: 5; Decimal part: 25

$num = 5.25;
$int_part = intval($num);
$dec_part = $num * 100 % 100;

This way is not involving string based functions, and is preventing accuracy problems which may arise in other math operations (such as having 0.49999999999999 instead of 0.5).

Haven't tested thoroughly with extreme values, but it works fine for me for price calculations.

But, watch out! Now from -5.25 you get: Integer part: -5; Decimal part: -25

In case you want to get always positive numbers, simply add abs() before the calculations:

$num = -5.25;
$num = abs($num);
$int_part = intval($num);
$dec_part = $num * 100 % 100;

Finally, bonus snippet for printing prices with 2 decimals:

$message = sprintf("Your price: %d.%02d Eur", $int_part, $dec_part);

...so that you avoid getting 5.5 instead of 5.05. ;)

MarcM
  • 2,173
  • 22
  • 32
2

This is the way which I use:

$float = 4.3;    

$dec = ltrim(($float - floor($float)),"0."); // result .3
alex
  • 479,566
  • 201
  • 878
  • 984
Serdar D.
  • 3,055
  • 1
  • 30
  • 23
1

Brad Christie's method is essentially correct but it can be written more concisely.

function extractFraction ($value) 
{
    $fraction   = $value - floor ($value);
    if ($value < 0)
    {
        $fraction *= -1;
    }

    return $fraction;
}

This is equivalent to his method but shorter and hopefully easier to understand as a result.

GordonM
  • 31,179
  • 15
  • 87
  • 129
1

I was having a hard time finding a way to actually separate the dollar amount and the amount after the decimal. I think I figured it out mostly and thought to share if any of yall were having trouble

So basically...

if price is 1234.44... whole would be 1234 and decimal would be 44 or

if price is 1234.01... whole would be 1234 and decimal would be 01 or

if price is 1234.10... whole would be 1234 and decimal would be 10

and so forth

$price = 1234.44;

$whole = intval($price); // 1234
$decimal1 = $price - $whole; // 0.44000000000005 uh oh! that's why it needs... (see next line)
$decimal2 = round($decimal1, 2); // 0.44 this will round off the excess numbers
$decimal = substr($decimal2, 2); // 44 this removed the first 2 characters

if ($decimal == 1) { $decimal = 10; } // Michel's warning is correct...
if ($decimal == 2) { $decimal = 20; } // if the price is 1234.10... the decimal will be 1...
if ($decimal == 3) { $decimal = 30; } // so make sure to add these rules too
if ($decimal == 4) { $decimal = 40; }
if ($decimal == 5) { $decimal = 50; }
if ($decimal == 6) { $decimal = 60; }
if ($decimal == 7) { $decimal = 70; }
if ($decimal == 8) { $decimal = 80; }
if ($decimal == 9) { $decimal = 90; }

echo 'The dollar amount is ' . $whole . ' and the decimal amount is ' . $decimal;
Jiyoon
  • 11
  • 3
1
$x = 1.24

$result = $x - floor($x);

echo $result; // .24
1

If you can count on it always having 2 decimal places, you can just use a string operation:

$decimal = 1.25;
substr($decimal,-2);  // returns "25" as a string

No idea of performance but for my simple case this was much better...

Ben Barreth
  • 1,675
  • 1
  • 15
  • 16
  • Note: if you do this, you should at least use round($decimal, 2); first to ensure you only have two digits as decimal. But you can not use this if you want to have correct math or handle money. – Ulrik McArdle Jul 23 '20 at 19:43
0

To prevent the extra float decimal (i.e. 50.85 - 50 give 0.850000000852), in my case I just need 2 decimals for money cents.

$n = 50.85;
$whole = intval($n);
$fraction = $n * 100 % 100;
fbaudet
  • 224
  • 4
  • 8
0

Try it this way... it's easier like this

$var = "0.98";

$decimal = strrchr($var,".");

$whole_no = $var-$decimal;

echo $whole_no;

echo str_replace(".", "", $decimal);
Everything good
  • 321
  • 4
  • 10
0

You could also use something like this:

preg_match("/([0-9]+)\.([0-9]+)/", $number, $matches);
Inc33
  • 1,747
  • 1
  • 20
  • 26
0

If you want the two halves to be explicitly type cast, then sscanf() is a great call.

Code: (Demo)

var_dump(sscanf(1.25, '%d%f'));

Output:

array(2) {
  [0]=>
  int(1)
  [1]=>
  float(0.25)
}

Or you can assign the two variables individually:

sscanf(1.25, '%d%f', $int, $float);
var_dump($int);
var_dump($float);

Casting the decimal portion as a float is particularly useful when, say, converting decimal expression of hours to hours and minutes. (Demo)

$decimalTimes = [
    6,
    7.2,
    8.78,
];

foreach ($decimalTimes as $decimalTime) {
    sscanf($decimalTime, '%d%f', $hours, $minutes);
    printf('%dh%02dm', $hours, round($minutes * 60));
    echo "\n";
}

Output:

6h00m
7h12m
8h47m  // if round() was not used, this would be 8h46m
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
-1

Not seen a simple modulus here...

$number         = 1.25;
$wholeAsFloat   = floor($number);   // 1.00
$wholeAsInt     = intval($number);  // 1
$decimal        = $number % 1;      // 0.25

In this case getting both $wholeAs? and $decimal don't depend on the other. (You can just take 1 of the 3 outputs independently.) I've shown $wholeAsFloat and $wholeAsInt because floor() returns a float type number even though the number it returns will always be whole. (This is important if you're passing the result into a type-hinted function parameter.)

I wanted this to split a floating point number of hours/minutes, e.g. 96.25, into hours and minutes separately for a DateInterval instance as 96 hours 15 minutes. I did this as follows:

$interval = new \DateInterval(sprintf("PT%dH%dM", intval($hours), (($hours % 1) * 60)));

I didn't care about seconds in my case.

Adambean
  • 1,096
  • 1
  • 9
  • 18
-3
val = -3.1234

fraction = abs(val - as.integer(val) ) 
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • 2
    Hi, do add a bit of explanation along with the code as it helps to understand your code. Code only answers are frowned upon. – Bhargav Rao Jan 10 '16 at 17:07