在32位PHP中处理大整数

在32位PHP中处理大整数,php,floating-point,int,floating-point-precision,Php,Floating Point,Int,Floating Point Precision,我有一个计算数字Luhn校验和的类。它将integer作为输入,并返回true或false以指示有效性或其他,或者如果输入的数据类型不正确,则抛出异常 代码如下(完整源代码位于on): 类Luhn扩展了abstr\Prop实现了iface\Prop { /** *测试给定数据是否通过Luhn检查。 * *@如果数据通过Luhn检查,则返回bool True *@throws\InvalidArgumentException *@见http://en.wikipedia.org/wiki/Luh

我有一个计算数字Luhn校验和的类。它将integer作为输入,并返回true或false以指示有效性或其他,或者如果输入的数据类型不正确,则抛出异常

代码如下(完整源代码位于on):

类Luhn扩展了abstr\Prop实现了iface\Prop
{
/**
*测试给定数据是否通过Luhn检查。
* 
*@如果数据通过Luhn检查,则返回bool True
*@throws\InvalidArgumentException
*@见http://en.wikipedia.org/wiki/Luhn_algorithm
*/
公共函数有效()
{
$data=$this->getData();
$valid=false;
开关(gettype($data))
{
大小写“NULL”:
$valid=true;
打破
“整数”情况:
//获取组成被测数字的数字序列
$digits=array_reverse(array_map('intval',str_split((string)$data));
//遍历数组,每两位数的值加倍
对于($i=0,$count=count($digits);$i<$count;$i++)
{
如果($i%2)
{
//两位数
如果($digits[$i]*=2)>9)
{
//处理双位数大于9的情况
$digits[$i]-=10;
$digits[]=1;
}
}
}
//如果数字总和以0结尾,则Luhn有效
$valid=((数组和($digits)%10)==0);
打破
违约:
//试图将检查应用于无效的数据类型
抛出new\InvalidArgumentException(_类__.'):此属性不能应用于类型为“.gettype($data)”的数据;
打破
}
报税表(有效);
}
}
我还建了一个充分锻炼的班

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

我想我可以在午餐时间(Windows7,XAMPP,32位PHP5.3)抽出一些时间来做这个类所属的项目,但我遇到的第一件事是单元测试失败

问题是,在32位的PHP构建中,如果数字超过32位整数的限制,则该数字会自动转换为浮点。我建议的解决方案是对float有一个特例。如果输入类型是float,并且它的值超出了可以用int表示的范围(PHP_int_MIN..PHP_int_MAX),那么我将对它进行编号以使其返回到一个数字字符串中。如果它在整数范围内,那么我将抛出一个异常

然而,这导致了它自身的问题。我知道浮点数离0越远,该数字的分辨率越低(给定数字和下一个可表示数字之间的增量越小)。在无法可靠地表示整数部分之前,必须离0多远才能表示数字的整数部分?(我不确定这是否真的很清楚,例如,在分辨率降到一个整数和下一个整数之间的差之前,限制是1000。我可以输入一个大于1000的数字,比如1001,但浮点数的限制意味着它最终是1001.9,四舍五入得到1002,这意味着我丢失了我的整数休息(休息)

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


编辑以添加:我想我可以修改扩展名以接受字符串而不是数字类型,然后验证它是否只包含使用正则表达式或其他类似技术的数字,但由于Luhn可检查数据是一个数字字符串,不知怎的,我觉得不正确。有一些PHP扩展可以处理bignum,但由于它们是扩展,而且这是一段框架代码,可能会部署在广泛的配置中,因此如果可能的话,我宁愿不依赖这些扩展的存在。除此之外,上述任何一项都不能解决一个问题,即如果给PHP一个大int,它会自动将其转换为float。我需要一种方法来检测是否发生了这种情况

如果需要精度,则不应使用浮点数


相反,特别是当您想要处理整数时(如果我理解正确的话),您可以尝试使用
bc*
函数:

如果您需要精度,您不应该使用浮点

相反,特别是当您想处理整数时(如果我理解正确的话),您可以尝试使用
gmp*
函数:

如果您无法使用该扩展,您可能会从

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);
    }
}