107

How can I check if a given number is within a range of numbers?

1

16 Answers 16

183

The expression:

($min <= $value) && ($value <= $max)

will be true if $value is between $min and $max, inclusively

See the PHP docs for more on comparison operators

Sign up to request clarification or add additional context in comments.

18 Comments

No it won't. Both comparison operators should be <=, or the operands of the second part of the expression should be swapped. ($value should not be greater than $max).
You must have added that comment while I was correcting my error... this expression is now correct
Depending on whether the OP really means "integer" when asking for "integer" this will produce false results when $value is a float. Also, since the comparison is loose, passing a string might produce false result, e.g. (0 <= 'string') && ('string' <= 10) ); is true due to type juggling.
@Gordon, only if you wish the boundary values to be treated inclusively... but a valid point, nonetheless
It's really missing a Python-like syntax: $min <= $value <= $max
|
135

You can use filter_var

filter_var(
    $yourInteger, 
    FILTER_VALIDATE_INT, 
    array(
        'options' => array(
            'min_range' => $min, 
            'max_range' => $max
        )
    )
);

This will also allow you to specify whether you want to allow octal and hex notation of integers. Note that the function is type-safe. 5.5 is not an integer but a float and will not validate.

Detailed tutorial about filtering data with PHP:

Comments

55

Community warning: this method us hugely inefficient. And becomes more inefficient with bigger ranges, wasting RAM and CPU to create an array and then traversing this array instead of simply comparing 2 numbers. Although for such small numbers, as used in the example, the difference is negligible, but this method is not recommended for the general purpose usage.

Might help:

if ( in_array(2, range(1,7)) ) {
    echo 'Number 2 is in range 1-7';
}

http://php.net/manual/en/function.range.php

6 Comments

Worth noting that has a memory cost due to the generation of the range.
@pr1nc3 but this solution is very slow and very memory hungry when it's a large range.
Agreed, this is way less elegant than the accepted solution and it will take much longer to execute on larger arrays because you have to perform a search on the array to find the value. It's faster, less memory hungry, and just as few lines to use the accepted solution.
Does not handle float values
As others commented, it seems range() will allocate all the items in the range to then compare just with the boundaries. If the range is big, this is a very bad solution in terms of memory use.
|
23

You could whip up a little helper function to do this:

/**
 * Determines if $number is between $min and $max
 *
 * @param  integer  $number     The number to test
 * @param  integer  $min        The minimum value in the range
 * @param  integer  $max        The maximum value in the range
 * @param  boolean  $inclusive  Whether the range should be inclusive or not
 * @return boolean              Whether the number was in the range
 */
function in_range($number, $min, $max, $inclusive = FALSE)
{
    if (is_int($number) && is_int($min) && is_int($max))
    {
        return $inclusive
            ? ($number >= $min && $number <= $max)
            : ($number > $min && $number < $max) ;
    }

    return FALSE;
}

And you would use it like so:

var_dump(in_range(5, 0, 10));        // TRUE
var_dump(in_range(1, 0, 1));         // FALSE
var_dump(in_range(1, 0, 1, TRUE));   // TRUE
var_dump(in_range(11, 0, 10, TRUE)); // FALSE

// etc...

1 Comment

So if one of my values is just a numeric string, I'll never get the correct result, neither an error message that would have told me me to cast the value. I really wonder why people are writing a code like this, deliberately planting such hard-to-debug issues
13
if (($num >= $lower_boundary) && ($num <= $upper_boundary)) {

You may want to adjust the comparison operators if you want the boundary values not to be valid.

Comments

6

You can try the following one-statement:

if (($x-$min)*($x-$max) < 0)

or:

if (max(min($x, $max), $min) == $x)

3 Comments

min() and max() will use comparision in the actual hardware implementation so doing both min and max and single comparision will result in always doing three in total. Instead, simply writing if ($min < $x and $x < $max) which will do two comparisions in worst case and only one if the value $x is smaller than $min limit. The variant with multiplication might be faster with assembler because it can use CPU pipelining very effectively but in case of PHP, I'd recommend testing that instead of assuming it's better than two compariosions with shortcut and in between.
This is literally a code obfuscation. Who writes formulas when you can simply use < and > operators?
@MikkoRantalainen : why not just do 3 compares that's friendly to CPU pipelining because they're all chained up, as such ::::::: if (($x < min) < ($x <= max)) { … } It has the pipelining advantage over short-circuiting brethrens, while keeping values of variables pristine, instead of the horror scenario in multiplication variants that will tell you neither +inf nor -inf belong to the closed interval of [ -inf, +inf ], because the subtractions end up generating operands of nan for the multiplication.
6

Some other possibilities:

if (in_array($value, range($min, $max), true)) {
    echo "You can be sure that $min <= $value <= $max";
}

Or:

if ($value === min(max($value, $min), $max)) {
    echo "You can be sure that $min <= $value <= $max";
}

Actually this is what is use to cast a value which is out of the range to the closest end of it.

$value = min(max($value, $min), $max);

Example

/**
 * This is un-sanitized user input.
 */
$posts_per_page = 999;

/**
 * Sanitize $posts_per_page.
 */
$posts_per_page = min(max($posts_per_page, 5), 30);

/**
 * Use.
 */
var_dump($posts_per_page); // Output: int(30)

Comments

0

using a switch case

    switch ($num){

        case ($num>= $value1 && $num<= $value2): 
            echo "within range 1";
        break;
        case ($num>= $value3 && $num<= $value4): 
            echo "within range 2";
        break;
        .
        .
        .
        .
        .

        default: //default
            echo "within no range";
        break;
     }

1 Comment

Should be switch(true), otherwise if $num == 0, the case logic fails because PHP tries to match 0 == ($num>= $value1 && $num<= $value2), etc. I've suggested this as an edit.
0

Another way to do this with simple if/else range. For ex:

$watermarkSize = 0;

if (($originalImageWidth >= 0) && ($originalImageWidth <= 640)) {
    $watermarkSize = 10;
} else if (($originalImageWidth >= 641) && ($originalImageWidth <= 1024)) {
    $watermarkSize = 25;
} else if (($originalImageWidth >= 1025) && ($originalImageWidth <= 2048)) {
    $watermarkSize = 50;
} else if (($originalImageWidth >= 2049) && ($originalImageWidth <= 4096)) {
    $watermarkSize = 100;
} else {
    $watermarkSize = 200;
}

Comments

0

I created a function to check if times in an array overlap somehow:

    /**
     * Function to check if there are overlapping times in an array of \DateTime objects.
     *
     * @param $ranges
     *
     * @return \DateTime[]|bool
     */
    public function timesOverlap($ranges) {
        foreach ($ranges as $k1 => $t1) {
            foreach ($ranges as $k2 => $t2) {
                if ($k1 != $k2) {
                    /* @var \DateTime[] $t1 */
                    /* @var \DateTime[] $t2 */
                    $a = $t1[0]->getTimestamp();
                    $b = $t1[1]->getTimestamp();
                    $c = $t2[0]->getTimestamp();
                    $d = $t2[1]->getTimestamp();

                    if (($c >= $a && $c <= $b) || $d >= $a && $d <= $b) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

Comments

0

Here is my little contribution:

function inRange($number) {
  $ranges = [0, 13, 17, 24, 34, 44, 54, 65, 200];
  $n = count($ranges);

  while($n--){
    if( $number > $ranges[$n] )
      return $ranges[$n]+1 .'-'. $ranges[$n + 1];
  }

Comments

0

I've created a simple helper function.

if ( !function_exists('number_between') )
{
    /**
     * number_between
     * 
     * @param {integer} $number
     * @param {array} $range [min, max]
     * @return {boolean}
     */
    function number_between(
            int $number, 
            array $range
    ){
        
        if(
                count($range) !== 2 || 
                is_numeric($range[0]) === FALSE || 
                is_numeric($range[1]) === FALSE
        ){
            throw new \Exception("number_between second parameter must contain two numbers.", E_WARNING);
        }
        
        if( 
                in_array($number, range($range[0], $range[1]))
        ){
            return TRUE;
        }else{
            return FALSE;
        }
    }
    
}

Comments

0
$searchInRange = 1;
$ranges = [
    1 => [
        'min_range' => 0.01,
        'max_range' => 199.99
    ],
    2 => [
        'min_range' => 200.00,
    ],
];


$rangeFound = false; 
foreach($ranges as $value => $range){
    if(filter_var($searchInRange, FILTER_VALIDATE_FLOAT, ['options' => $range])){
        echo 'serach value: '. $searchInRange .' is in range key:' .$value;
        $rangeFound = true;
        break;
    }
}

3 Comments

Can someone explain why this is wrong (minus)?
perhaps because your code is doing some odd things, like returning the key variable $value for no apparent reason, and your filter_var() function is testing $cartTotal, which is not defined in your code snippet, instead of $value. Also, someone from 2011 already gave an example of filter_var(), so why are you duplicating his answer with the extra looping and complexity? AND, you haven't provided an explanation of how filter_var() works, or a link to the documentation.
if range includes zero, this function will return incorrect results
-1
function limit_range($num, $min, $max)
{
  // Now limit it
  return $num>$max?$max:$num<$min?$min:$num;
}

$min = 0;  // Minimum number can be
$max = 4;  // Maximum number can be
$num = 10;  // Your number
// Number returned is limited to be minimum 0 and maximum 4
echo limit_range($num, $min, $max); // return 4
$num = 2;
echo limit_range($num, $min, $max); // return 2
$num = -1;
echo limit_range($num, $min, $max); // return 0

Comments

-1

I have function for my case

Use:

echo checkRangeNumber(0);
echo checkRangeNumber(1);
echo checkRangeNumber(499);
echo checkRangeNumber(500);
echo checkRangeNumber(501);
echo checkRangeNumber(3001);
echo checkRangeNumber(999);

//return

0
1-500
1-500
1-500
501-1000
3000-3500
501-1000

function checkRangeNumber($number, $per_page = 500)
{
    //$per_page = 500; // it's fixed number, but... 

    if ($number == 0) {
        return "0";
    }

    $num_page = ceil($number / $per_page); // returns 65
    $low_limit = ($num_page - 1) * $per_page + 1; // returns 32000
    $up_limit = $num_page * $per_page; // returns 40
    return  "$low_limit-$up_limit";
}

Comments

-3

Thank you so much and I got my answer by adding a break in the foreach loop and now it is working fine.

Here are the updated answer:

foreach ($this->crud->getDataAll('shipping_charges') as $ship) {
  if ($weight >= $ship->low && $weight <= $ship->high) {
      $val = $ship->amount;
      break;
      }
      else
      {
        $val = 900;
      }
     }
     echo $val ;

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.