处理32位PHP中的大整数

3
我有一个用于计算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);
    }
}

我还建立了一个完整的单元测试来检验这个类。

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

我想在工作午餐时间利用一些空余时间(Windows 7、XAMPP、32位PHP 5.3)来处理这个类所在项目的问题,但我遇到的第一个问题就是单元测试失败。

问题在于,在32位的PHP构建中,如果数字超出32位整数的范围,它就会被默默地转换为浮点数。我的解决方案是针对浮点数进行特殊处理。如果输入类型是浮点数,并且其值超出了int(PHP_INT_MIN .. PHP_INT_MAX)可以表示的范围,则我将使用number_format()将其格式化为数字字符串。如果它在整数范围内,则会抛出一个异常。
然而,这也带来了它自己的问题。我知道,随着浮点数越来越远离0,数字的分辨率越小(给定数字和下一个可表示数字之间的增量越小)。您必须远离0多远,才能在无法可靠地表示整数部分之前表示整数部分?(我不确定是否真正清楚,因此例如,假设限制为1000,然后分辨率低于一个int和下一个之间的差异。我可以输入大于1000的数字,比如1001,但浮点数的限制意味着它最终变成1001.9,并四舍五入得到1002,这意味着我失去了感兴趣的价值)。
有没有可能检测到浮点数的分辨率损失何时成为问题?编辑补充:我想我可以修改扩展,接受字符串而不是数字类型,并使用正则表达式或其他类似技术验证它只包含数字,但是由于Luhn可检查数据是一串数字字符串,这在某种程度上感觉不对。PHP有一些处理大数的扩展,但是由于它们是扩展程序,并且这是一个框架代码片段,可能部署在各种配置上,因此如果可能的话,最好不要依赖这些扩展的存在。此外,以上所有内容都没有解决以下问题:如果您给PHP一个大整数,它会将其静默转换为浮点数。我需要一种检测到这种情况发生的方法。
2个回答

7
如果需要精确度,就不应该使用浮点数。相反,特别是当您想使用整数时(如果我理解正确的话),可以尝试使用bc*函数:BCMath任意精度数学

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接