PHP: Elegant way to avoid division by zero

后端 未结 7 465
小鲜肉
小鲜肉 2020-12-30 07:19

Much like this site, my current project has reputation and in the script that I\'m working on I need to calculate the ratio between two users\' reputations.

         


        
相关标签:
7条回答
  • 2020-12-30 07:45

    I don’t recommend to change any user’s reputation artificially solely to make the math work. Instead you can do this:

    function calc_rep_ratio($self, other)
    {
        if ($self->rep != 0) {
            return $other->rep / $self->rep;
        } else {
            return NAN;
        }
    }
    

    Then use the function

    $defender->ratio = calc_rep_ratio($defender, $attacker);
    $attacker->ratio = calc_rep_ratio($attacker, $defender);
    

    In the presentation, you can check for the number

    if (is_nan($user->ratio)) {
        echo 'No ratio available';
    } else {
        echo $user->ratio;
    }
    
    0 讨论(0)
  • 2020-12-30 07:46

    This is the way I would do it.

    $defender->ratio = ($defender->rep === 0) ? 0 : $attacker->rep / $defender->rep;
    
    0 讨论(0)
  • 2020-12-30 07:46

    Use a ternary operator to check if the divider is zero or not.

    $attacker->ratio = $attacker->rep > 0 ? $defender->rep / $attacker->rep : 1;
    $defender->ratio = $defender->rep > 0 ? $attacker->rep / $defender->rep : 1;
    

    Use whatever you wish instead of the value 1 as default.

    0 讨论(0)
  • 2020-12-30 08:00

    Based upon the other answers I'll assume you only update the ratio if it's not zero (Remember you asked for elegance not clarity):

    if( !empty($attacker->rep) ) { 
        $attacker->ratio = $defender->rep / $attacker->rep;
    }
    

    PHP treats 0 as empty.

    0 讨论(0)
  • 2020-12-30 08:04

    If you are using PHP > 5.3 you could use the ternary operator ?:

    $attacker->ratio = $defender->rep / ($attacker->rep ?: 1);
    $defender->ratio = $attacker->rep / ($defender->rep ?: 1);
    

    This means if the variable before the operator is false or empty the value afterwards would be returned otherwise the first value is returned

    Example below:

    $attacker->rep = 0;
    $defender->rep = 55;
    $attacker->ratio = $defender->rep / ($attacker->rep ?: 1); // returns 55 / 1 = 55
    $defender->ratio = $attacker->rep / ($defender->rep ?: 1); // returns 0 / 55 = 0
    
    0 讨论(0)
  • 2020-12-30 08:06

    Assuming positive numbers are valid then ensure the lowest divisor value will be 1.

    $defender->ratio = $attacker->rep / max($defender->rep, 1);
    

    // --------------------------------------------

    suggested code by someone else,

    @php_nub_qq suggested alternate code...
    In today's php

    $defender->ratio = $attacker->rep / ($defender->rep ?? 1);
    

    Alas, this code provided by @php_nub_qq does not work in PHP 7.4 ;-( see @OceanBt in the comments... I thank them for the correction! :)

    so, Here I am maintaining code that I never was interested in. And now, is shown to be PHP version specific! Here is the correction...

    $y = 100/($x ?: 1);

    Why am I doing this? 1) Notice my code still works fine! Avoid 'clever features' for production code. 2) Because someone believes that have a 'better answer' doesn't mean they do!

    I don't mind doing this maintainance of the code of someone else! This is the real world! We have to do this. I posted it because:
    I really am trying to help programmers to learn.

    // My thoughts about the 'improvement' to what I posted...

    imo, that suggestion of yours isn't the same as my approach! I specifically used 'max' as it forces a limit on a range of numbers. You can nest the 'min' and 'max' functions also to force a limited range.

    Your method is a 'selection' and not why I did the answer I did. :)

    0 讨论(0)
提交回复
热议问题