【问题标题】:How to get sign of a number?如何获得数字的符号?
【发布时间】:2011-11-25 06:35:35
【问题描述】:

有没有一种(简单的)方法可以在 PHP 中获取与gmp_signDocs 相当的数字(整数)的“符号”:

  • -1 否定
  • 0 零
  • 1 阳性

我记得有某种比较功能可以做到这一点,但我现在找不到它。

我很快编译了这个 (Demo) 来完成这项工作,但也许还有更漂亮的东西(比如单个函数调用?),我想将结果映射到一个数组:

$numbers = array(-100, 0, 100);

foreach($numbers as $number)
{
   echo $number, ': ', $number ? abs($number) / $number : 0, "\n";
}

(此代码可能会遇到浮点精度问题)

相关:Request #19621 Math needs a "sign()" function

【问题讨论】:

  • @Tomalak Geret'kal:有时您会寻求反馈,对吧? ;)
  • @Orbling:好问题,可能是因为它已经安装了?让我试试:)

标签: php math sign


【解决方案1】:

这是一个很酷的单线,可以高效可靠地为您完成:

function sign($n) {
    return ($n > 0) - ($n < 0);
}

【讨论】:

  • 好吧,您不会遇到整数溢出问题或浮点精度问题,因为没有对 $n 执行任何算术运算。此外,IEEE 浮点数确实遵循排中定律(¬(A &gt; B) ⇒ A ≤ B¬(A &lt; B) ⇒ A ≥ B),因此您不会得到满足这两个条件的非零数并产生不正确的符号 0。最后,-00 都被 IEEE 规范视为等于 0,因此在这两种情况下都将返回 false,产生 0 的符号。它适用于所有数字输入。将NAN 输入函数会产生1 - 1 = 0,这和我想的一样好。
【解决方案2】:

在 PHP 7 中,您应该使用 combined comparison operator (&lt;=&gt;):

$sign = $i <=> 0;

【讨论】:

  • 这很好,我喜欢它。宇宙飞船操作员。但它会破坏尚未升级到 PHP 7.0 的服务器。可悲的是那些仍然存在。
  • AFAIK,在 PHP 中 &lt;=&gt; 的结果不保证是 +10-1,它可以是任何正整数而不是 +1 和任何负整数而不是 -1(参见 cmets here 中的讨论)。所以,TS 可能需要一些函数来处理&lt;=&gt; 的结果。
【解决方案3】:

我测试过的问题中的上述变体,效果也很好,没有浮点问题:

min(1, max(-1, $number))

编辑: 上面的代码在大于-1 和小于1 的范围内有一个浮点数(问题是关于整数)的缺陷,可以用以下shorty 修复:

min(1, max(-1, $number == 0 ? 0 : $number * INF))

那个浮动NAN 仍然存在缺陷,使其始终返回-1。那可能不正确。相反,可能还想返回0

min(1, max(-1, (is_nan($number) or $number == 0) ? 0 : $number * INF))

【讨论】:

  • 这对于整数来说是可以的,但是如果有人将这个解决方案粘贴到浮点数上,他会遇到麻烦。
  • @rocksportrocker:特别是对于 NAN 和 INF 值。对于整数也有溢出。
  • 不适用于0.3(或从-11 的所有数字)
  • @hakre:在这种情况下,从 -1 到 1 的所有数字都返回 0,而不是它们的符号
  • @Yukulélé:编辑了帖子。希望这更有帮助。请记住,该问题要求输入整数,而不是浮点数。
【解决方案4】:

您可以嵌套三元运算符:

echo $number, ': ',  ($number >= 0 ? ($number == 0 ? 0 : 1) : -1 )

这对浮点精度没有问题,避免了浮点除法。

【讨论】:

  • @Gordon 你能提供一个链接吗?
  • 这里是:php.net/manual/en/language.operators.comparison.php,原因是 (true?'true':false?'t':'f') 将返回什么并不明显(它是 't',而不是 '真的')。 Rocksportrocker 用括号来保证求值的顺序,没关系。
【解决方案5】:

这个表格有什么问题?

if ( $num < 0 )
{
  //negative
}
else if ( $num == 0 )
{
  //zero
}
else
{
  //positive
}

或三元:

$sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );

不确定abs 与值比较的性能,但您可以使用:

$sign = $num ? $num / abs($num) : 0;

你可以将它们中的任何一个变成一个函数:

function valueSign($num)
{
  return $sign = $num < 0 ? -1 : ( $num > 0 ? 1 : 0 );
  //or
  return $sign = $num ? $num / abs($num) : 0;
}

我想你可能在谈论gmp_cmp,你可以称之为gmp_cmp( $num, 0 );

【讨论】:

  • 表达式应该代表一个值:(-1, 0, 1)
  • @hakre,我不确定你的意思。
  • @hakre,忘记了那部分,添加了零检查。
【解决方案6】:

我认为 gmp_sign 效率不高,因为它需要 GMP 或字符串。 ($n ? abs($n)/$n : 0) 在数学上是正确的,但除法需要时间。 对于浮点数来说,最小/最大解决方案似乎变得不必要的复杂。

($n > 0) - ($n 0 ? 1 : 0) 进行一两次测试并且没有算术,它应该是最有效的。 但我认为这种差异与大多数用例无关。

【讨论】:

    【解决方案7】:

    我知道这已经晚了,但是简单地将数字除以自身的 abs() 怎么样?

    类似:

    function sign($n) {
        return $n/(abs($n));
    }
    

    将任何你想要的 div 错误处理设置为零。

    【讨论】:

    • 好点,边缘可能有点粗糙(不是说其他​​答案是完整的,我的旧答案也有粗糙的边缘 IIRC),它不仅被零除,而且 INF 需要处理除法运算符。
    【解决方案8】:

    使用strcmpDocs:

    echo $number, ': ', strcmp($number, 0), "\n";
    

    【讨论】:

    • 这适用于数字(作为字符串)吗?我认为这就是我正在考虑的功能,但我不确定它是否真的在做这项工作。
    • 是的。试试看吧。
    • 酷!如果它总是-1, 0 or 1,文档有点不精确,但是,我会在代码中尝试它。谢谢!
    • 这很优雅,但效率不高。将 int 转换为字符串所需的时间比与 0 的比较要长得多。
    • 我现在已经测试了几个小时。如果$number 实际上是一个字符串(并且表示零,如"n/a"),这将不起作用(min(max) 在这里起作用)。请注意,这是一个侧面案例,只是将其留作笔记。它通常工作得很好,但不是用于表示数值 0 的字符串变量,正如我们在 PHP 中所知道的那样。 @rocksportrocker:PHP 中没有真正的实际类型,例如 string 或 intever,因此转换参数在我看来是虚假的。无论如何都会对它进行微优化,以密切关注它。
    【解决方案9】:

    这是一个没有循环的:

    function sign($number){
        echo $number, ': ', $number ? abs($number) / $number : 0, "\n";
    }
    
    $numbers = array(-100, 0, 100);
    
    array_walk($numbers, 'sign');
    

    【讨论】:

      猜你喜欢
      • 2010-12-01
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      • 2014-05-13
      • 2019-08-25
      • 1970-01-01
      • 2022-12-04
      • 2013-06-27
      相关资源
      最近更新 更多