0

I'm looking for the fastest way to get this test. So functions, operands and everything else is allowed. I tried with the following regex (I'm not an expert):

0\.[0-9]+|100\.0+|100|[1-9]\d{0,1}\.{0,1}[0-9]+

It works except that it erroneously accept 0.0 or 0.000000 and so on. Also it's not the most appropriated and fastest way.

(if anybody wants to fix the regex to don't allow those 0.00 values it would be appreciated)`

Unihedron
  • 10,902
  • 13
  • 62
  • 72
kuus
  • 453
  • 1
  • 5
  • 15

3 Answers3

4

Use bccomp

This is a perfect use case for BCMath functions.

function compare_numberic_strings($number) {
    if (
        is_numeric($number) &&
        bccomp($number, '0') === 1 &&
        bccomp($number, '100') === -1
    ) {
       return true;
    }
    return false;
}

echo compare_numberic_strings('0.00001');
//returns true

echo compare_numberic_strings('50');
//returns true

echo compare_numeric_strings('100.1');    
//returns false

echo compare_numeric_strings('-0.1');
//returns false

From the manual:

Returns 0 if the two operands are equal, 1 if the left_operand is larger than the right_operand, -1 otherwise.

Community
  • 1
  • 1
Tek
  • 2,888
  • 5
  • 45
  • 73
  • Is this faster than the above answer: http://stackoverflow.com/a/27986661/1938970 ? – kuus Jan 16 '15 at 15:10
  • 1
    @kuus First of all, read this: http://stackoverflow.com/questions/3470990/is-micro-optimization-worth-the-time . But to answer your question, yes. These functions are written internally in C. Which is much faster than PHP itself. PLUS. And this is a big PLUS. You should never use `<`, `>` to compare floats. *Ever.* There's a big fat warning on the PHP.net as well about this http://php.net/manual/en/language.types.float.php#language.types.float.comparison . That's what the BCMath functions are for. – Tek Jan 16 '15 at 15:17
  • @Tek: bollocks... these functions are written in C -> yes, so? C is much faster than PHP -> yes. What language is PHP written in? => **C**. No matter how you look at it `$val > 0 && $val <= 100` is comparing 2 `zval` (the internal representation of a PHP variable). `bccomp` is _calling a function_, which is more expensive than comparing 2 scalar values, Always. – Elias Van Ootegem Jan 16 '15 at 15:21
  • @Tek Thanks, I know all the talking, thinking and problems about micro-optimization, but I still wanted to know what was the fastest :) – kuus Jan 16 '15 at 15:23
  • @EliasVanOotegem Either way comparing floats using traditional operators is a big no no. – Tek Jan 16 '15 at 15:26
  • @kuus You're welcome. Sure beats having to use expensive regexes ;) – Tek Jan 16 '15 at 15:29
  • @Tek: Why would comparing 2 `double`'s be so terribly unreliable in this particular case? So much so, even, that you'd rather parse a stringified number into a struct, to compare that struct using a [ton of helper functions and heap memory](https://github.com/php/php-src/blob/master/ext/bcmath/bcmath.c#L513). Check the implementation of `bccomp` before claiming anything regarding its performance. It clearly wasn't designed to be _fast_, it was designed to counter possible rounding issues with the IEEE754 spec, but OP isn't doing any arithmetic here – Elias Van Ootegem Jan 16 '15 at 15:36
  • @EliasVanOotegem Because we don't know what his data set looks like and maybe neither does he. Everything in there is for a good reason, they're not wasted calculations. It's safer to use functions written specially for this purpose so we can avoid questions like these: http://stackoverflow.com/questions/5230305/php-integer-and-float-comparison-mismatch – Tek Jan 16 '15 at 15:54
  • @Tek: The question you linked to, like any other question concerning issues with floating point numbers, performs computations. OP specified in a comment to my answer, that the numbers he's after are extracted from a string. No computation, no rounding issues. I'm just advocating to keep things simple – Elias Van Ootegem Jan 16 '15 at 17:01
  • @EliasVanOotegem Even then you need to specify what you need the smallest acceptable difference when comparing such as http://stackoverflow.com/questions/3148937/compare-floats-in-php It's just better to use BCMath functions and not have to worry about floating point numbers at all. Plus you can guarantee any kind of computation with them. You don't want to accidentally compute on a floating point because you're used to using normal operators and comparing them afterwards. It's better to become acquainted with proper programming techniques in PHP – Tek Jan 16 '15 at 17:11
  • @Tek: Again: linked question deals with computation of floating-point numbers. Besides, a very common (much more common than using bmath), easier alternative in both PHP _and_ C is to not use decimals (just use `long` or `int`, and divide by 100 for output). Yes, floating-point arithmetic is error-prone, but honestly, KISS. I know you'll probably link to yet another question, or tell me to put in `.1 + .2` in a JS console, but frankly, this is a pointless discussion, and is very much off topic here. Let's either agree that PHP is not the best tool for arithmetic, or agree to disagree – Elias Van Ootegem Jan 16 '15 at 18:33
  • I agree, although there's still much to learn. lol @ the js console part – Tek Jan 16 '15 at 18:34
3

No need for regex:

if (is_numeric($val) && $val > 0 && $val <= 100)
{
    echo '$val is number (int or float) between 0 and 100';
}

Demo

Update

It turns out you're getting the numeric values from a string. In that case, it would be best to extract all of them using a regex, something like:

if (preg_match_all('/\d+\.?\d*/', $string, $allNumbers))
{
    $valid = [];
    foreach ($allNumbers[0] as $num)
    {
        if ($num > 0 && $num <= 100)
            $valid[] = $num;
    }
}

You can leave out the is_numeric check, because the matched strings are guaranteed to be numeric anyway...

Renaat De Muynck
  • 3,267
  • 1
  • 22
  • 18
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • `is_numeric(1e0)` returns `true` - so I think regex is the sollution – violator667 Jan 16 '15 at 14:58
  • Maybe, but anyway for my use case I'll probably need to first do a regex to extract the number (int or float) from a string with something like this `([0-9]+\.{0,1}[0-9]*)` and then check that the number is in the range with the posted solution. – kuus Jan 16 '15 at 15:05
  • @kuus You don't need a regex. Look at my answer. – Tek Jan 16 '15 at 15:08
  • @violator667: that's because `1e0` _is_ numeric, it's the same as `1^0` (1 to the power of 0), which is, by definition, and therefore a valid value... try `var_dump(1e0);` in php, it dumps 1 – Elias Van Ootegem Jan 16 '15 at 15:13
  • @Tek my problem is that the number is in a string with other stuff like: `sometext($),@31.321312(rew)` so I need to extact it from there and then do the check. – kuus Jan 16 '15 at 15:14
  • @kuus: extract numeric values using a regex like so: `preg_match_all('/\d+\.?\d*/', $string, $allNumbers)`, then process all numbers using my answer, but you can leave out the `is_numeric` check, because `preg_match_all` already guarantees the matches to be numeric – Elias Van Ootegem Jan 16 '15 at 15:16
  • actually I need a regex a bit more like this `(0\.[0-9]*|[1-9]{0,1}\d+\.{0,1}[0-9]+)` because I can't allow a value `013`, it would return true in the range check but in my use case it's not ok. – kuus Jan 16 '15 at 15:34
  • This doesn't work with a calculated float if the value is something like 100.000001493894, or 0.9999985378683 – Tim Feb 22 '18 at 14:29
  • @Tim nothing you can do about that, really... those numbers cause rounding issues due to the fact that PHP uses the IEEE 754 double precision format. There are extensions specifically built to get around some of the headaches that come with these type of numbers (BC math comes to mind). There probably are some libraries you could use, too – Elias Van Ootegem Feb 22 '18 at 17:28
  • comparing int and float is bad. – Inoyatulloh Aug 01 '19 at 05:45
  • @Inoyatulloh internally, they're `zval`'s, which will be coerced to comparable types anyway. Sure, coersion happens beyond your control, but then the internal conversion is no different to a cast. At least, that was how it worked back in the day when I was developing PHP extensions, and delved deep down into the bowels of the Zend engine – Elias Van Ootegem Aug 01 '19 at 15:53
0

I think your regex pattern should look like this:

^\d{1,2}$|(100)

Demo

violator667
  • 469
  • 4
  • 19