7

PHP provides different functions for computing modulus:

  1. Modulus operator %: echo ($a % $b);
  2. fmod()
  3. bcmod()
  4. gmp_mod()

Which function should be used that considered safe and efficient? considering the (devision by zero issue that described here: Division by zero error while using modulus and floating numbers?

3
  • 3
    Perhaps you should state how you expect a zero to be handled?
    – d-_-b
    Commented Aug 6, 2013 at 1:11
  • please edit and improve it, i asked this question to be used as reference
    – user1646111
    Commented Aug 6, 2013 at 1:13
  • Akam, what should happen when a zero is encountered is specific to the problem/domain. If you are going to make a wiki outlining what those functions do, go for it.
    – d-_-b
    Commented Aug 6, 2013 at 1:19

4 Answers 4

21
+100
  1. Only the modulus operator (%), and fmod are native

  2. The modulus operator cannot handle numbers beyond 2^32 (on PHP running x86 architecture)

  3. fmod runs faster than bcmod/gmp_mod ~benchmark

  4. bcmod doesn't work with floats ~here

I believe it is best to use fmod, simply because it's within Math Functions, runs way faster than other function, and most importantly, can handle large numbers and floats.

If you don't plan on using numbers past the limit or floats, use % as it should be the fastest.

3
  • 2. ...large numbers ~34%4294967296 change to 2^32 which is large integer on 32 bit OS
    – user1646111
    Commented Aug 12, 2013 at 15:34
  • Being within Math Functions does not make a function better or faster than others, one should understand their implementation to judge that. If one plans to stay under the limit of the floats it's still unsafe to use %, one should stay under max int to achieve safeness.
    – sanyi
    Commented Aug 14, 2013 at 20:22
  • % operator does behave a bit weird (PHP 5.4): 1.98 % 1 results in 0 instead of 0.98
    – Erfan
    Commented Jul 15, 2016 at 6:27
2

All functions are safe to use provide one knows what is doing:

  1. Modulus operator: is fast, precise but you need to stay under the max int. There is no division by zero issue whatsoever in this terms.

  2. fmod: stil fast, floating point operation speed is no longer an issue in the past 10 years, but is tricky. Floating point numbers can reach much higher values but their precision not. So working with big numbers will increasingly introduce rounding errors. So will not solve anything the modulus operator lacks instead will introduce precision issues.

  3. bcmod and gmp_mod are simmilar. The difference is that this functions use different implementation (modules) of arbitrary precision arithmetic. Their usage differs, but their results not: Theoretically the size of the numbers supported by this libraries is only limited by the amount of free memory, so practically the result will be always good and precise, however the algorithms used are overkill both computationally and from memory point of view.

1

You can still use the modulus operator and it can still be safe provided you plan to expect a zero at some point, as shown below.

if ($y > 0) {
  // Do the calculation
}
else {
  // Do this instead
}

For just hiding the warnings could also use an Error Control Operator. By using the @ Operator, the error is suppressed.

However with % an integer can only get so large before it gets converted into a float, hence the introduction of bcmod and fmod but please note they both have their own limitations.

I'd reccommend GMP or perhaps take a look at one of the other enhanced maths functions, there is also BCMath

Since you mentioned something safe there is a class for this: Eval Math

Here's an example using fmod

<?php
echo fmod('4294967296', 34);
?>

outputs 18

2
  • can you please try this: echo(34%4294967296)
    – user1646111
    Commented Aug 8, 2013 at 15:48
  • The answer as far as I'm aware, on a 32-Bit system is actually 0 because it can't be represented by a number. As a work around, you could possibly use php.net/manual/en/function.unpack.php
    – user2069217
    Commented Aug 9, 2013 at 16:23
0

Note that fmod is NOT equivalent to this basic function:

    <?php 
    function modulo($a, $b) { 
    return $a - $b * floor($a / $b); 
    } 
    ?> 

because fmod() will return a value with the same sign as $a. In other words the floor() function is not correct as it rounds towards -INF instead of towards zero.

To emulate fmod($a, $b) the correct way is:

    <?php 
    function fmod($a, $b) { 
    return $a - $b * (($b < 0) ? ceil($a / $b) : floor($a / $b))); 
    } 
    ?> 

Note that both functions will throw a DIVISION BY ZERO if $b is null.

The first function modulo() above is the mathematical function which is useful for working on cyclic structures (such as calender computions or trignonometric functions :

    - fmod($a, 2*PI) returns a value in [0..2*PI) if $a is positive 
    - fmod($a, 2*PI) returns a value in [-2*PI..0] if $a is negative 
    - modulo($a, 2*PI) returns a value always in [0..2*PI) independantly of the sign of $a