PHP Doku:: Rest einer Fließkommadivision - function.fmod.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzMathematische ErweiterungenMathematische FunktionenMathematische Funktionenfmod

Ein Service von Reinhard Neidl - Webprogrammierung.

Mathematische Funktionen

<<floor

getrandmax>>

fmod

(PHP 4 >= 4.2.0, PHP 5)

fmodRest einer Fließkommadivision

Beschreibung

float fmod ( float $x , float $y )

Berechnet den Fließkommarest der Division des Dividenden x durch den Divisor y. Der Rest r ist definiert als 'x = i * y + r' für ein Ganzzahliges Divisionsergebnis i. Ist y ungleich null so hat das Ergebnis das gleiche Vorzeichen wie x und ist kleiner als y.

Parameter-Liste

x

Der Dividend

y

Der Divisor

Rückgabewerte

Der Fließkommarest der Division x/y

Beispiele

Beispiel #1 fmod() Beispiel

<?php
$x 
5.7;
$y 1.3;
$r fmod($x$y);
// $r ist 0.5 weil 4 * 1.3 + 0.5 = 5.7
?>


18 BenutzerBeiträge:
- Beiträge aktualisieren...
dePijd
10.02.2010 15:37
This class ran through several unit tests and fixes all failures found in bugs.php.net

<?php
abstract class MyNumber {
    public static function
isZero($number, $precision = 0.0000000001)
    {
       
$precision = abs($precision);
        return -
$precision < (float)$number && (float)$number < $precision;
    }
    public static function
isEqual($number1, $number2)
    {
        return
self::isZero($number1 - $number2);
    }
    public static function
fmod($number1, $number2)
    {
       
$rest = fmod($number1, $number2);
        if (
self::isEqual($rest, $number2)) {
            return
0.0;
        }
        if (
mb_strpos($number1, ".") === false) {
           
$decimals1 = 0;
        } else {
           
$decimals1 = mb_strlen($number1) - mb_strpos($number1, ".") - 1;
        }
        if (
mb_strpos($number2, ".") === false) {
           
$decimals2 = 0;
        } else {
           
$decimals2 = mb_strlen($number2) - mb_strpos($number2, ".") - 1;
        }
        return (float)
round($rest, max($decimals1, $decimals2));
    }
}
?>
linkboss at gmail dot com
18.10.2009 14:49
You can also use the modulo operator '%', which returns the same result :

<?php
$var1
= 5;
$var2 = 2;

echo
$var1 % $var2; //Returns 1
echo fmod($var1,$var2); //Returns the same
?>
matrebatre
20.05.2008 21:09
I always use this:

function modulo($n,$b) {
return $n-$b*floor($n/$b);
}

And it appears to work correctly.
ysangkok at gmail dot com
1.07.2007 18:37
Please note that this:
<?php
function custom_modulo($var1, $var2) {
 
$tmp = $var1/$var2;

  return (float) (
$var1 - ( ( (int) ($tmp) ) * $var2 ) );
}

$par1 = 1;
$par2 = 0.2;

echo
"fmod:          ";
var_dump(fmod ( $par1 , $par2 ));
echo
"custom_modulo: ";
var_dump(custom_modulo ( $par1 , $par2 ));
?>

gives this:

fmod:          float(0.2)
custom_modulo: float(0)

Fmod does not deliver the desired result, therefore I made my own.
cory at lavacube dot net
9.12.2005 7:13
I don't believe that is correct.

Try this out using your patch:
<?php

echo duration( mktime(0, 0, 0, 1, 0, 2006)-time() );

?>

As of right now, this will read:
1 month, 22 days, 24 hours, 49 minutes, 15 seconds

Which is completely incorrect. Seeing as how it is the 9th of December.

The real real flaw here is how the 'year' and 'month' periods are calculated. As most months vary in length...

Thank you very much SnakeEater251 for pointing this out.

The quickest way to get slightly more accurate results, is to use averages based on one "true" year, which is 365.25 days.

Change the year and month to:
      'year'       => 31557600, // one 'true year' (365.25 days)
      'month'    => 2629800, // one 'true year' divided by 12 :-)

I will work on developing a true fix, for pin-point accuracy. ;-)

 - Cory Christison
SnakeEater251
27.11.2005 7:16
Note on the code given by cory at lavacube dot net.
You will recieve better results by not using floor and using round instead. As you continue increasing to larger amounts of time you will notice that the outputted time is off by large amounts.

so instead of $temp = floor( $int_seconds / $length );
we would use  $temp = round( $int_seconds / $length );

<?php

function duration( $int_seconds=0, $if_reached=null )
{
  
$key_suffix = 's';
  
$periods = array(
                  
'year'        => 31556926,
                  
'month'        => 2629743,
                  
'day'        => 86400,
                  
'hour'        => 3600,
                  
'minute'    => 60,
                  
'second'    => 1
                  
);

  
// used to hide 0's in higher periods
  
$flag_hide_zero = true;

  
// do the loop thang
  
foreach( $periods as $key => $length )
   {
      
// calculate
      
$temp = round( $int_seconds / $length );

      
// determine if temp qualifies to be passed to output
      
if( !$flag_hide_zero || $temp > 0 )
       {
          
// store in an array
          
$build[] = $temp.' '.$key.($temp!=1?'s':null);

          
// set flag to false, to allow 0's in lower periods
          
$flag_hide_zero = false;
       }

      
// get the remainder of seconds
      
$int_seconds = fmod($int_seconds, $length);
   }

  
// return output, if !empty, implode into string, else output $if_reached
  
return ( !empty($build)?implode(', ', $build):$if_reached );
}

?>
cory at lavacube dot net
26.11.2005 9:38
A more formal way for generating duration strings:

<?php

function duration( $int_seconds=0, $if_reached=null )
{
   
$key_suffix = 's';
   
$periods = array(
                   
'year'        => 31556926,
                   
'month'        => 2629743,
                   
'day'        => 86400,
                   
'hour'        => 3600,
                   
'minute'    => 60,
                   
'second'    => 1
                   
);

   
// used to hide 0's in higher periods
   
$flag_hide_zero = true;

   
// do the loop thang
   
foreach( $periods as $key => $length )
    {
       
// calculate
       
$temp = floor( $int_seconds / $length );

       
// determine if temp qualifies to be passed to output
       
if( !$flag_hide_zero || $temp > 0 )
        {
           
// store in an array
           
$build[] = $temp.' '.$key.($temp!=1?'s':null);

           
// set flag to false, to allow 0's in lower periods
           
$flag_hide_zero = false;
        }

       
// get the remainder of seconds
       
$int_seconds = fmod($int_seconds, $length);
    }

   
// return output, if !empty, implode into string, else output $if_reached
   
return ( !empty($build)?implode(', ', $build):$if_reached );
}

?>

Simple use:
<?php

   
echo duration( mktime(0, 0, 0, 1, 1, date('Y')+1) - time(), 'Some fancy message to output if duration is already met...' );

?>

Enjoy. :-)
cory at simplesystems dot ca
23.11.2005 2:39
Just a note on the previous note by Ryan Means:

Instead of using explode() to get the number before the decimal point, would be to use floor()... floor() rounds fractions down, which is exactly what is needed.

His same example using floor();

<?PHP
$totalsec
=XXXXXXX; //Replace the X's with a int value of seconds

$daysarray = floor( $totalsec/86400 );

$partdays = fmod($totalsec, 86400);
$hours = floor( $partdays/3600 );

$parthours = fmod($partdays, 3600);
$min = floor( $parthours/60 );

$sec = fmod($parthours, 60);

echo
"days " . $days . "<br>";
echo
"hours " . $hours . "<br>";
echo
"minutes " . $min . "<br>";
echo
"seconds " . $sec . "<br>";
?>
Ryan Means
11.05.2005 15:15
If your given a number of seconds and you want to turn it into Days, hours, minutes, and seconds:
(this is very useful when using the Unix Time Epoch to find the difference from one time to the other)

For Example:
I posted in a bb at one date.. when I post a Unix Time Epoch was marked..
Then When I go back and view it again 2 weeks later I generate the Unix Time Epoch for the current time.
Then take the current time - the posting time, this gives the number of seconds since the post.
Then use the below equations to get days, hours, minutes, and seconds since the post was made:

<?PHP
$totalsec
=XXXXXXX; //Replace the X's with a int value of seconds

$daysarray = explode(".", ($totalsec/86400));
$days = $daysarray[0];

$partdays = fmod($totalsec, 86400);
$hoursarray = explode(".", ($partdays/3600));
$hours = $hoursarray[0];

$parthours = fmod($partdays, 3600);
$minarray = explode(".", ($parthours/60));
$min = $minarray[0];

$sec = fmod($parthours, 60);

echo
"days " . $days . "<br>";
echo
"hours " . $hours . "<br>";
echo
"minutes " . $min . "<br>";
echo
"seconds " . $sec . "<br>";
?>
sam dot fullman at verizon
24.02.2005 16:29
This function behaves wierd in negative regions.  If you have something like an angle that goes through 360 degress of rotation and your angle goes negative, then fmod of -1 should be 359, right?

Here's a way to get that result, so that you get a phase shift vs. just a "negative fmod":

$h= -30; //same as 330 degrees

//handle negative
if($h<0){
    while(true){
        $fail++; if($fail>100)break; //in case loop gets tied up
        $h+=360;
        if($h>=0)break;
    }
}
$h=fmod($h,360);

echo $h;  //will say 330 degrees - we phase shifted up until positive.
rocan
20.02.2005 3:10
john at digitizelife dot com:

Well not sure how your comment applys to fmod..

but their is a sure simpler way of coping with situations like this..

its called a bit field (bit masking)
 
e.g.

/* Categories */
bin     dec   cat
0001 - 1 - Blue
0010 - 2 - Red
0100 - 4 - Green 
1000 - 8 - Yellow

/* Permissions */
0010 - 2   - Bob
0101 - 5    - John
1011 - 11  - Steve
1111-  15 - Mary

to find out the permissions for each user you simple need to do a bitwise AND 

$steve_auth=11;

function get_perm($auth)
{
    $cats["Blue"]=1;
    $cats["Red"]=2;
    $cats["Green"]=4;
    $cats["Yellow"]=8;
    $perms=array();
    foreach($cats as $perm=>$catNum)
    {
          if($auth & $catNum)
                $perms[$perm]=true;

    }

    return $perms;
}

print_r(get_perm($steve_auth));
/*
returns
Array
(
    [Blue] => 1
    [Red] => 1
    [Yellow] => 1
)
*/

This is far simpler than your prime number idea, in fact you dont even need a function in any tests for the permmsions on a user you can do them directly using the bitwise and operator.

You may want to read the following

http://en.wikipedia.org/wiki/Bitmask
http://uk2.php.net/manual/en/language.operators.bitwise.php
john at digitizelife dot com
25.01.2005 1:09
In the process of writing an authentication process for my software, I came across the need for a permissions function. Basically, I wanted to use prime numbers to indicate a specified permission 'group' or 'category'. For example, the categories could be asigned a prime number as follows;

/* Categories */
2 - Blue
3 - Red
5 - Green
7 - Yellow

Then, a permission level can be assigned to a user as follows;

/* Permissions */
3 - Bob
10 - John
42 - Steve
210 - Mary

Using the prime number assigned to the specified category, you can specify access to each category by multiplying the allowed categories together. For example, Bob only has access to Red, whereas Steve has access to Red, Blue and Yellow.

Only prime numbers work because the resulting permission number can only be devided evenly by 1, itself, and one of the prime numbers. So, a script can be written to look for the multiples of the permission number. Here is what I came up with;

function get_perm($auth) {

    /* initialize variables */
    $perm = array();
    $count = 0;

    for ($x = 1; $x <= $auth; $x++) {
        $result = $auth / $x;
        if (!ereg("[.]", $result)) { // is whole number
            $n = 0;
            for ($y = 1; $y <= $x; $y++) {
                $result = $x / $y;
                if (!ereg("[.]", $result)) { // is whole number
                    $n++;
                }
            }
            if ($n == 2) {
                $count++;
                $perm[$count] = $x;
            }
        }
    }
    return($perm);
}

The function starts by looking for multiples of $auth (the given authorization number [42]). Then it checks to see if that multiple is prime. If it is, the script inserts the value into array $perm.

When called, the function will return the array of permissions for the given authorization number. For example;

$auth = 42;

$perm = get_perm($auth);

$perm will now contain the numbers; 2, 3, 7 since 2*3*7=42. The values can be parsed by using a simple loop.

/* count number of permisions */
$count = count($perm);

/* print permisions */
while ($count > 0) {
    echo "$perm[$count]<br>";
    $count--;
}

If there is a more simple way to acheive the previous results, please feel free to comment (and e-mail me). I orignally thought PHP was able to do this simply by mod($auth). However, I was wrong.
jphansen at uga dot edu
10.01.2005 20:44
fmod() does not mirror a calculator's mod function. For example, fmod(.25, .05) will return .05 instead of 0 due to floor(). Using the aforementioned example, you may get 0 by replacing floor() with round() in a custom fmod().

<?
function fmod_round($x, $y) {
   
$i = round($x / $y);
    return
$x - $i * $y;
}

var_dump(fmod(.25, .05)); // float(0.05)
var_dump(fmod_round(.25, .05)); // float(0)
?>
konstantin at rekk dot de
27.05.2004 17:10
If you need to reduce an integer to zero if zero and 1 if not, you can use

$sign = (integer)(boolean)$integer;

instead of

$sign = $integer > 0 ? 1 : 0;

it is faster from 100 operations on (at least on my machine).
alex at xelam dot net
16.02.2004 22:19
Integer Modulo

If you want the remainder of the division of two Integers rather than Floats, use "%"; eg:

<?php
$a
= 4;
$b = 3;

print(
$a % $b);
?>

Will output "1".
Jon
9.05.2003 22:25
for those w/o fmod, here is q lil' add-on function you can use to replicate it:

function fmodAddOn($x,$y)
{
        $i = floor($x/$y);

        // r = x - i * y
        return $x - $i*$y;
}
fjeanson at yahoo dot com
10.03.2003 5:16
For those of you still using PHP 4.1.X and below.. fmod is not available. You can easily check if a variable a multiple of 2 by doing the following which is compatible with 4.1.X and below:

$var; //variable to check if multiple of 2 or not

$stype = gettype($var/2); //returns the type of the result.
if($stype == "integer"){
    echo "$var is a multiple of two! Yay!";
} else {
    echo "$var is NOT a multiple of two! Yay, I guess!";
}

since 3/2 = 1.5 its a float..
4/2 = 2 its an integer..

$stype will be equal to "double" if the variable is a float.. for historical reasons.

voila.
picaune at hotmail dot com
10.03.2003 0:57
NAN (.net Equivalent = Double.NaN) means "Not-a-Number".
Some ways to get NaN are modulo 0, and square root of 0.



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)