文字

fmod

(PHP 4 >= 4.2.0, PHP 5)

fmod返回除法的浮点数余数

说明

float fmod ( float $x , float $y )

返回被除数(x)除以除数(y)所得的浮点数余数。余数( r )的定义是:x = i * y + r,其中 i 是整数。如果 y 是非零值,则 r x 的符号相同并且其数量值小于 y

参数

x

被除数

y

除数

返回值

x/y的浮点数余数。

范例

Example #1 fmod() 的使用

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

用户评论:

[#1] timo underscore teichert at yahoo dot de [2014-10-27 13:40:17]

The behaviour of this function seems to have changed over time.

<?php

echo fmod(3,5); 
// php 5.3.2 outputs -2
// php 5.3.8 outputs 3

echo fmod(2,5); 
// php 5.3.2 outputs 2
// php 5.3.8 outputs 2

?>


- Timo

[#2] KRAER [2014-01-28 11:23:16]

To create a list of primes in a bash based on php wich can be resumed after breaking I did use fmod() and some snippets offered by two more users here on php comments.

This will output :
"prime;difference-between-last-and-current-prime"

So credit goes to them. I only did the logfile output.

This will function up to whatever fmod supports as highest value. Just enter the $end value. And do a touch to the logfile followed by chmod 666 so php can access it.

<?php 
function tailCustom($filepath$lines 1$adaptive true) {
 
        
// Open file
        
$f = @fopen($filepath"rb");
        if (
$f === false) return false;
 
        
// Sets buffer size
        
if (!$adaptive$buffer 4096;
        else 
$buffer = ($lines 64 : ($lines 10 512 4096));
 
        
// Jump to last character
        
fseek($f, -1SEEK_END);
 
        
// Read it and adjust line number if necessary
        // (Otherwise the result would be wrong if file doesn't end with a blank line)
        
if (fread($f1) != "\n"$lines -= 1;
        
        
// Start reading
        
$output '';
        
$chunk '';
 
        
// While we would like more
        
while (ftell($f) > && $lines >= 0) {
 
            
// Figure out how far back we should jump
            
$seek min(ftell($f), $buffer);
 
            
// Do the jump (backwards, relative to where we are)
            
fseek($f, -$seekSEEK_CUR);
 
            
// Read a chunk and prepend it to our output
            
$output = ($chunk fread($f$seek)) . $output;
 
            
// Jump back to where we started reading
            
fseek($f, -mb_strlen($chunk'8bit'), SEEK_CUR);
 
            
// Decrease our line counter
            
$lines -= substr_count($chunk"\n");
 
        }
 
        
// While we have too many lines
        // (Because of buffer size we might have read too many)
        
while ($lines++ < 0) {
 
            
// Find first newline and remove all text before that
            
$output substr($outputstrpos($output"\n") + 1);
 
        }
 
        
// Close file and return
        
fclose($f);
        return 
trim($output);
 
    }

function 
isPrime$num 

    for( 
$i 2$i*$i <= $num$i++ ) 
        if( !
fmod($num,$i) ) 
            return 
FALSE

    return 
TRUE


$logfile 'prim_save.log';

$lastline explode(";"tailCustom($logfile));
$begin = ($lastline[0] +1);
$lastprime $lastline[0];

$end 999999999999999999999999999999999999

$fp fopen($logfile'a');
//Lineformat    $i.';'.$difference.';'."\n"

for($i $begin$i<$end$i++) 

    if(
isPrime($i) == TRUE
    { 
        
$difference $i $lastprime;
        
fputs($fp,$i.';'.$difference.';'."\n");
        
$lastprime $i;
    } 
}

fclose($fp);
?>

[#3] Adrien Gibrat [2013-07-05 22:33:38]

There is an elegant way to do compute gcm :
https://en.wikipedia.org/wiki/Greatest_common_divisor

    // Recursive function to compute gcd (euclidian method)
    function gcd ($a, $b) {
        return $b ? gcd($b, $a % $b) : $a;
    }
    // Then reduce any list of integer
    echo array_reduce(array(42, 56, 28), 'gcd'); // === 14

If you want to work with floating points, use approximation :

    function fgcd ($a, $b) {
        return $b > .01 ? fgcd($b, fmod($a, $b)) : $a; // using fmod
    }
    echo array_reduce(array(2.468, 3.7, 6.1699), 'fgcd'); // ~= 1.232

You can use a closure in PHP 5.3 :

    $gcd = function ($a, $b) use (&$gcd) { return $b ? $gcd($b, $a % $b) : $a; };

[#4] verdy_p [2012-12-12 02:38:48]

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

[#5] dePijd [2010-02-10 06:37:25]

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($restmax($decimals1$decimals2));
    }
}
?>

[#6] linkboss at gmail dot com [2009-10-18 05:49:25]

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
?>

[#7] matrebatre [2008-05-20 12:09:45]

I always use this:

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

And it appears to work correctly.

[#8] ysangkok at gmail dot com [2007-07-01 09:37:26]

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.

[#9] cory at lavacube dot net [2005-12-08 22:13:10]

I don't believe that is correct.

Try this out using your patch:
<?php

echo durationmktime(000102006)-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

[#10] SnakeEater251 [2005-11-26 22:16:10]

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 )
       {
           
// 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 );
}

?>

[#11] cory at lavacube dot net [2005-11-26 00:38:46]

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 )
        {
            
// 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 durationmktime(00011date('Y')+1) - time(), 'Some fancy message to output if duration is already met...' );

?>


Enjoy. :-)

[#12] cory at simplesystems dot ca [2005-11-22 17:39:56]

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($totalsec86400);
$hours floor$partdays/3600 );

$parthours fmod($partdays3600);
$min floor$parthours/60 );

$sec fmod($parthours60);

echo 
"days " $days "<br>";
echo 
"hours " $hours "<br>";
echo 
"minutes " $min "<br>";
echo 
"seconds " $sec "<br>";
?>

[#13] Ryan Means [2005-05-11 06:15:35]

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($totalsec86400);
$hoursarray explode(".", ($partdays/3600));
$hours $hoursarray[0];

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

$sec fmod($parthours60);

echo 
"days " $days "<br>";
echo 
"hours " $hours "<br>";
echo 
"minutes " $min "<br>";
echo 
"seconds " $sec "<br>";
?>

[#14] sam dot fullman at verizon [2005-02-24 07:29:58]

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.

[#15] rocan [2005-02-19 18:10:32]

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.


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


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));


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

[#16] jphansen at uga dot edu [2005-01-10 11:44:49]

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().

<?php
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)
?>

[#17] konstantin at rekk dot de [2004-05-27 08:10:51]

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).

[#18] alex at xelam dot net [2004-02-16 13:19:37]

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".

[#19] picaune at hotmail dot com [2003-03-09 15:57:47]

NAN (.net Equivalent = Double.NaN) means "Not-a-Number".
Some ways to get NaN are modulo 0, and square root of 0.

上一篇: 下一篇: