drk7700 2019-03-16 05:26
浏览 21

PHP排序似乎出现故障

### Result of sort 

sort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);

{ ...
[51]=> float(11.903327742296) 
[52]=> int(5) 
[53]=> float(13.165002546636) 
[54]=> float(14.478273306964) 
[55]=> float(4.6264742674547) 
[56]=> float(13.290508819344) 
[57]=> float(15.686809055276) } 

### Result or rsort

rsort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);

{
[0]=> float(15.686809055276) 
[1]=> float(14.478273306964) 
[2]=> float(13.290508819344)
[3]=> float(13.165002546636) 
[4]=> float(11.903327742296) 
[5]=> int(5) 
[6]=> float(4.6264742674547)
... }

echo var_export($keys_arranged);

array ( 0 => 3.142678516658294, 1 => 1.0, 2 => 1.0, 3 => 14.478273306963985, 4 => 13.165002546635966, 5 => 1.0, 6 => 1.0005037081114851, 7 => 1.0, 8 => 4.6264742674547001, 9 => 15.686809055275578, 10 => 1.0, 11 => 11.903327742295504, 12 => 13.29050881934397, 13 => 1.0, 14 => 1.0, 15 => 3.5421134937189365, 16 => 1.0, 17 => 0.010999999999999999, 18 => 3.2999566681750605, 19 => 5, 20 => 1.2282984802843129, 21 => 1.0, 22 => 2.9748253120971184, 23 => 0.44855992975075798, 24 => 0.99999999999999989, 25 => 3.8350475954623371, 26 => 1.0625975061426283, 27 => 1.0000072792091179, 28 => 0.99999987785487132, 29 => 1, 30 => 0.0, 31 => 1.0, 32 => 1.0, 33 => 1.0, 34 => 0.0, 35 => 1.0972568578553616, 36 => 1.0, 37 => 1.4077661823957415, 38 => 1.0, 39 => 0.0, 40 => 3.6038030347555705, 41 => 1.0, 42 => 1.0, 43 => 1.0636876768842174, 44 => 1.0, 45 => NAN, 46 => 1.0, 47 => NAN, 48 => NAN, 49 => NAN, 50 => NAN, 51 => 1.0, 52 => 1.0, 53 => NAN, 54 => 0.99958680716631509, 55 => 1.0, 56 => NAN, 57 => 1.0, )

I got some incorrect result from array_multisort. It has 8 different keys and all the keys but this key(say A) works fine.

To figure out why that happened, I played with A in the array. And I could see that not only in the function of array_multisort, but also in 'sort' function, an incorrect result prompted as well.

As you can see the result of rsort seems okay, the result of sort works strangely when it comes to 13.16 < 14.47 < 4.62 < 13.29 < 15.68

Does anyone know why this occurred?

// Data in readible format

array (
0 => 3.142678516658294, 
1 => 1.0, 
2 => 1.0, 
3 => 14.478273306963985, 
4 => 13.165002546635966, 
5 => 1.0, 
6 => 1.0005037081114851, 
7 => 1.0, 
8 => 4.6264742674547001, 
9 => 15.686809055275578, 
10 => 1.0, 
11 => 11.903327742295504, 
12 => 13.29050881934397, 
13 => 1.0, 
14 => 1.0, 
15 => 3.5421134937189365, 
16 => 1.0, 
17 => 0.010999999999999999, 
18 => 3.2999566681750605, 
19 => 5, 
20 => 1.2282984802843129, 
21 => 1.0, 
22 => 2.9748253120971184, 
23 => 0.44855992975075798, 
24 => 0.99999999999999989, 
25 => 3.8350475954623371, 
26 => 1.0625975061426283, 
27 => 1.0000072792091179, 
28 => 0.99999987785487132, 
29 => 1, 
30 => 0.0, 
31 => 1.0, 
32 => 1.0, 
33 => 1.0, 
34 => 0.0, 
35 => 1.0972568578553616, 
36 => 1.0, 
37 => 1.4077661823957415, 
38 => 1.0, 
39 => 0.0, 
40 => 3.6038030347555705, 
41 => 1.0, 
42 => 1.0, 
43 => 1.0636876768842174, 
44 => 1.0, 
45 => NAN, 
46 => 1.0, 
47 => NAN, 
48 => NAN, 
49 => NAN, 
50 => NAN, 
51 => 1.0, 
52 => 1.0, 
53 => NAN, 
54 => 0.99958680716631509, 
55 => 1.0, 
56 => NAN, 
57 => 1.0, )
  • 写回答

1条回答 默认 最新

  • drwu24647 2019-03-16 08:05
    关注

    It seems as you actually do have discovered a bug. On large arrays containing NaN values, represented by the NAN constant in PHP, the built-in function sort fails.

    The comparision with NaN should always result as non-ordered as mentioned by kuh-chan in the question comments. However, as soon as there is at least one operand NaN, in recent (March 2019) versions of PHP the spaceship operator <=> returns 1 (first operand greater than second one) and -1 (first operand less than second one) in some other versions.

    echo var_dump( NAN   <=> 1.23  );
    echo var_dump( 1.23  <=> NAN   );
    echo var_dump( NAN   <=> -1.23 );
    echo var_dump( -1.23 <=> NAN   );
    echo var_dump( NAN   <=> 0     );
    echo var_dump( NAN   <=> NAN   );
    

    I'm not very famimilar with the internals of the Zend engine. However, I guess the sort algorithm terminates too soon on large arrays with several NaN values, likely in order to the order comparision algorithm alway returns "greater (or less) than" which probably leads to multiple exchanges of the same elements.

    I experienced that calling sort multiple times seems to continue the sorting. However, that would not be a proper workaround.

    You can use a custom comparision algorithm with usort instead. If you want to order NaN at the start of the array, return -1 when the first operand is NaN, 1 when the second operand is NaN and 0 (equal) if both are. Otherwise return the comparision result of the spaceship operator.

    usort($keys_arranged,
      function(&$v1, &$v2)
      {
        switch( (is_nan($v1) ? 1 : 0) | (is_nan($v2) ? 2 : 0) )
        {
          case 0: return $v1 <=> $v2;
          case 1: return -1;
          case 2: return 1;
          case 3: return 0;
        }
      }
    );
    

    Similar bitwise logic as above, but in a more compressive and direct form:

    usort( $keys_arranged,
           function(&$v1, &$v2){ return -2 === ($b = (is_nan($v1) ? -1 : -2) ^ (is_nan($v2) ? -1 : 0)) ? $v1 <=> $v2 : $b; }
         );
    
    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题