array_unique 具有 SORT_NUMBERIC 行为
array_unique with SORT_NUMBERIC behaviour
我偶然发现了一些奇怪的东西,我不明白为什么它会这样。
我有一个数字数组,它们都是唯一的:
$array = [
98602142989816970,
98602142989816971,
98602142989816980,
98602142989816981,
98602142989816982,
98602142989816983,
98602142989820095,
98602142989820096,
98602142989822060,
98602142989822061,
];
var_dump($array);
array(10) {
[0]=>
int(98602142989816970)
[1]=>
int(98602142989816971)
[2]=>
int(98602142989816980)
[3]=>
int(98602142989816981)
[4]=>
int(98602142989816982)
[5]=>
int(98602142989816983)
[6]=>
int(98602142989820095)
[7]=>
int(98602142989820096)
[8]=>
int(98602142989822060)
[9]=>
int(98602142989822061)
}
如果我这样做 print_r(array_unique($array));
一切都很好,我得到:
Array
(
[0] => 98602142989816970
[1] => 98602142989816971
[2] => 98602142989816980
[3] => 98602142989816981
[4] => 98602142989816982
[5] => 98602142989816983
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
但是如果我添加 SORT_NUMERIC
标志 print_r(array_unique($array, SORT_NUMERIC));
我得到:
Array
(
[0] => 98602142989816970
[6] => 98602142989820095
[8] => 98602142989822060
)
为什么只返回这 3 个数字?
更新: 我是64位系统
对于 sort
函数,我手动打乱了一些值,因为在原始数组中它们已经排序。
如果我这样做 sort($array);
那么响应就是预期的:
Array
(
[0] => 98602142989816970
[1] => 98602142989816971
[2] => 98602142989816980
[3] => 98602142989816981
[4] => 98602142989816982
[5] => 98602142989816983
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
但是对于 sort($array, SORT_NUMERIC);
,它们的排序不正确:
Array
(
[0] => 98602142989816970
[1] => 98602142989816982
[2] => 98602142989816983
[3] => 98602142989816980
[4] => 98602142989816981
[5] => 98602142989816971
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
您 运行 遇到了那个规模的精度和浮点运算问题。如果您有兴趣,可以在 Is floating point math broken? 上找到更多信息,但我认为这不算是它的重复。
取你的前两个数字:
php > var_dump((float) 98602142989816970 === (float) 98602142989816971);
bool(true)
php > var_dump((float) 98602142989816970, (float) 98602142989816971);
float(9.8602142989817E+16)
float(9.8602142989817E+16)
在内部,这就是 PHP 使用 SORT_NUMERIC
比较数组中的值时发生的情况,深入 numeric_compare_function
。
sort
遇到同样的问题,请参阅 https://3v4l.org/02UUB(显然没有值从数组中删除,因为这只发生在 array_unique
中 - 它们只是没有正确排序)
简而言之,对于这种大小的数字(或者特别是相对于它们的比例非常接近的数字),SORT_NUMERIC
是不可靠的。如果可以,坚持将它们作为字符串进行比较。
代码在 32 位 PHP 或 64 位版本下运行会有所不同,因为那里的整数也有 32 位或 64 位长。
$array = [
98602142989816970,
98602142989816971,
98602142989816980,
98602142989816981,
98602142989816982,
98602142989816983,
98602142989820095,
98602142989820096,
98602142989822060,
98602142989822061,
];
echo '<pre>';
var_dump(PHP_INT_MAX,$array);
32 位系统的结果:
int(2147483647)
array(10) {
[0]=>
float(9.8602142989817E+16)
[1]=>
float(9.8602142989817E+16)
[2]=>
float(9.8602142989817E+16)
[3]=>
float(9.8602142989817E+16)
[4]=>
float(9.8602142989817E+16)
[5]=>
float(9.8602142989817E+16)
[6]=>
float(9.860214298982E+16)
[7]=>
float(9.860214298982E+16)
[8]=>
float(9.8602142989822E+16)
[9]=>
float(9.8602142989822E+16)
}
PHP直接把数值转为浮点数,因为都大于PHP_INT_MAX.
64 位系统的结果:
int(9223372036854775807)
array(10) {
[0]=>
int(98602142989816970)
[1]=>
int(98602142989816971)
[2]=>
int(98602142989816980)
[3]=>
int(98602142989816981)
[4]=>
int(98602142989816982)
[5]=>
int(98602142989816983)
[6]=>
int(98602142989820095)
[7]=>
int(98602142989820096)
[8]=>
int(98602142989822060)
[9]=>
int(98602142989822061)
}
32位系统中的一个array_unique减少了数组,因为有些值也超过了float的精度
如果不使用 SORT_NUMERIC 选项,array_unique() 和 sort() 对于 64 位版本可以正常工作。
我偶然发现了一些奇怪的东西,我不明白为什么它会这样。
我有一个数字数组,它们都是唯一的:
$array = [
98602142989816970,
98602142989816971,
98602142989816980,
98602142989816981,
98602142989816982,
98602142989816983,
98602142989820095,
98602142989820096,
98602142989822060,
98602142989822061,
];
var_dump($array);
array(10) {
[0]=>
int(98602142989816970)
[1]=>
int(98602142989816971)
[2]=>
int(98602142989816980)
[3]=>
int(98602142989816981)
[4]=>
int(98602142989816982)
[5]=>
int(98602142989816983)
[6]=>
int(98602142989820095)
[7]=>
int(98602142989820096)
[8]=>
int(98602142989822060)
[9]=>
int(98602142989822061)
}
如果我这样做 print_r(array_unique($array));
一切都很好,我得到:
Array
(
[0] => 98602142989816970
[1] => 98602142989816971
[2] => 98602142989816980
[3] => 98602142989816981
[4] => 98602142989816982
[5] => 98602142989816983
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
但是如果我添加 SORT_NUMERIC
标志 print_r(array_unique($array, SORT_NUMERIC));
我得到:
Array
(
[0] => 98602142989816970
[6] => 98602142989820095
[8] => 98602142989822060
)
为什么只返回这 3 个数字?
更新: 我是64位系统
对于 sort
函数,我手动打乱了一些值,因为在原始数组中它们已经排序。
如果我这样做 sort($array);
那么响应就是预期的:
Array
(
[0] => 98602142989816970
[1] => 98602142989816971
[2] => 98602142989816980
[3] => 98602142989816981
[4] => 98602142989816982
[5] => 98602142989816983
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
但是对于 sort($array, SORT_NUMERIC);
,它们的排序不正确:
Array
(
[0] => 98602142989816970
[1] => 98602142989816982
[2] => 98602142989816983
[3] => 98602142989816980
[4] => 98602142989816981
[5] => 98602142989816971
[6] => 98602142989820095
[7] => 98602142989820096
[8] => 98602142989822060
[9] => 98602142989822061
)
您 运行 遇到了那个规模的精度和浮点运算问题。如果您有兴趣,可以在 Is floating point math broken? 上找到更多信息,但我认为这不算是它的重复。
取你的前两个数字:
php > var_dump((float) 98602142989816970 === (float) 98602142989816971);
bool(true)
php > var_dump((float) 98602142989816970, (float) 98602142989816971);
float(9.8602142989817E+16)
float(9.8602142989817E+16)
在内部,这就是 PHP 使用 SORT_NUMERIC
比较数组中的值时发生的情况,深入 numeric_compare_function
。
sort
遇到同样的问题,请参阅 https://3v4l.org/02UUB(显然没有值从数组中删除,因为这只发生在 array_unique
中 - 它们只是没有正确排序)
简而言之,对于这种大小的数字(或者特别是相对于它们的比例非常接近的数字),SORT_NUMERIC
是不可靠的。如果可以,坚持将它们作为字符串进行比较。
代码在 32 位 PHP 或 64 位版本下运行会有所不同,因为那里的整数也有 32 位或 64 位长。
$array = [
98602142989816970,
98602142989816971,
98602142989816980,
98602142989816981,
98602142989816982,
98602142989816983,
98602142989820095,
98602142989820096,
98602142989822060,
98602142989822061,
];
echo '<pre>';
var_dump(PHP_INT_MAX,$array);
32 位系统的结果:
int(2147483647)
array(10) {
[0]=>
float(9.8602142989817E+16)
[1]=>
float(9.8602142989817E+16)
[2]=>
float(9.8602142989817E+16)
[3]=>
float(9.8602142989817E+16)
[4]=>
float(9.8602142989817E+16)
[5]=>
float(9.8602142989817E+16)
[6]=>
float(9.860214298982E+16)
[7]=>
float(9.860214298982E+16)
[8]=>
float(9.8602142989822E+16)
[9]=>
float(9.8602142989822E+16)
}
PHP直接把数值转为浮点数,因为都大于PHP_INT_MAX.
64 位系统的结果:
int(9223372036854775807)
array(10) {
[0]=>
int(98602142989816970)
[1]=>
int(98602142989816971)
[2]=>
int(98602142989816980)
[3]=>
int(98602142989816981)
[4]=>
int(98602142989816982)
[5]=>
int(98602142989816983)
[6]=>
int(98602142989820095)
[7]=>
int(98602142989820096)
[8]=>
int(98602142989822060)
[9]=>
int(98602142989822061)
}
32位系统中的一个array_unique减少了数组,因为有些值也超过了float的精度
如果不使用 SORT_NUMERIC 选项,array_unique() 和 sort() 对于 64 位版本可以正常工作。