应对32位PHP中的大整数

Gor*_*onM 3 php floating-point int floating-point-precision

我有一个类来计算一个数字的Luhn校验和.它将整数作为输入并返回true或false以指示有效性或其他方式,或者如果给出不适当的数据类型作为输入则抛出异常.

代码如下(完整源代码在GitHub上):

class Luhn extends abstr\Prop implements iface\Prop
{
    /**
     * Test that the given data passes a Luhn check. 
     * 
     * @return bool True if the data passes the Luhn check
     * @throws \InvalidArgumentException 
     * @see http://en.wikipedia.org/wiki/Luhn_algorithm
     */
    public function isValid ()
    {
        $data   = $this -> getData ();
        $valid  = false;

        switch (gettype ($data))
        {
            case 'NULL'     :
                $valid  = true;
            break;
            case 'integer'  :
                // Get the sequence of digits that make up the number under test
                $digits = array_reverse (array_map ('intval', str_split ((string) $data)));
                // Walk the array, doubling the value of every second digit
                for ($i = 0, $count = count ($digits); $i < $count; $i++)
                {
                    if ($i % 2)
                    {
                        // Double the digit
                        if (($digits [$i] *= 2) > 9)
                        {
                            // Handle the case where the doubled digit is over 9
                            $digits [$i]    -= 10;
                            $digits []      = 1;
                        }
                    }
                }
                // The Luhn is valid if the sum of the digits ends in a 0
                $valid  = ((array_sum ($digits) % 10) === 0);
            break;
            default         :
                // An attempt was made to apply the check to an invalid data type
                throw new \InvalidArgumentException (__CLASS__ . ': This property cannot be applied to data of type ' . gettype ($data));
            break;
        }

        return ($valid);
    }
}
Run Code Online (Sandbox Code Playgroud)

我还建立了一个完整的单元测试来锻炼课程.

我的主要开发环境是在OSX Lion下运行64位构建PHP 5.3和Apache的工作站.我还在Apache下使用运行64位Apache和PHP 5.4的笔记本电脑.除此之外,我还有一个运行64位Apache和PHP 5.3的Ubuntu Linux虚拟机.正如预期的那样,单元测试对所有这些都很好.

我认为我可以在工作午餐(Windows 7,XAMPP,32位PHP 5.3)上有一些空余时间来处理这个类所属的项目,但我遇到的第一件事是单元测试失败.

问题是,在32位版本的PHP上,如果超过32位整数的限制,则数字会自动转换为浮点数.我建议的解决方案是浮动的特殊情况.如果输入类型是float,并且它的值超出了可以用int表示的范围(PHP_INT_MIN .. PHP_INT_MAX),那么我将number_format()它返回到一串数字.如果它在整数范围内,那么我将抛出异常.

然而,这导致了它自己的问题.我知道你用浮点数从0得到的距离越远,数字的分辨率越小(给定数字和下一个可表示数字之间的增量越小).在你不能再可靠地表示整数部分之前,你必须在多大程度上离开0才能表示数字的整数部分?(我不确定这是否真的很清楚,所以例如,在分辨率低于一个int和下一个之间的差值之前说限制是1000.我可以输入一个大于1000的数字,比如1001,但是限制了浮点数意味着它最终为1001.9并且舍入它产生1002,这意味着我已经失去了我感兴趣的值).

是否有可能检测到分辨率损失何时成为浮点数的问题?

编辑添加:我想我可以修改扩展名以接受字符串而不是数字类型,然后验证它只包含带有正则表达式或其他类似技术的数字,但由于Luhn可检查数据是一串数字,所以不知怎的,我觉得对我不对.PHP有扩展可以处理bignums,但由于它们是扩展,这是一段可能部署在各种配置上的框架代码,我宁可不依赖于这种扩展.如果可能的话,扩展.此外,以上都没有解决这个问题:如果你给PHP一个大的int,它会默默地将它转换为float.我需要一种检测这种情况的方法.

Pas*_*TIN 7

如果你需要精度,你不应该使用浮子.

相反,特别是当您想要使用整数时(如果我理解正确),您可以尝试使用这些bc*函数:BCMath Arbitrary Precision Mathematics