2012-05-20 57 views
3

我有一個用於計算一個數字的Luhn校驗和的類。它將整數作爲輸入,並返回true或false來指示有效性或否則,或者如果給出不適當的數據類型作爲輸入,則會引發異常。在32位PHP應對大整數

的代碼如下(完整的源代碼是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); 
    } 
} 

我還內置了全unit test行使類。

我的主要開發環境是在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),午餐在這個類是一部分該項目的工作,但我遇到的第一件事就是在一些空閒時間是失敗的單元測試。

問題是,在PHP的32位版本中,如果數字超過了32位整數的限制,則該數字會默默轉換爲浮點數。我建議的解決方案是有一個浮動的特殊情況。如果輸入類型是float,並且它的值超出了可以用int(PHP_INT_MIN .. PHP_INT_MAX)表示的範圍,那麼我將使用number_format()將其重新轉換爲一串數字。如果它在整數範圍內,那麼我會拋出一個異常。

但是,這會導致它自己的問題。我知道從0到浮點數的距離越遠,數字的分辨率越小(給定數字與下一個可表示數字之間的增量越小)。在你不能可靠地表示整數部分之前,你需要得到多少距離才能表示數字的整數部分? (我不確定是否真的很清楚,比如說,在分辨率低於一個int和下一個int之間的差值之前,限制是1000,我可以輸入一個大於1000的數字,比如說1001,但是限制浮點數意味着它最終爲1001.9,並將其舍入爲1002,這意味着我失去了我感興趣的價值)。

是否有可能檢測出分辨率損失何時會成爲浮點數的問題?

編輯補充:我想我可以修改擴展名,接受一個字符串,而不是數字類型,然後驗證它包含只有一個正則表達式或一些其他類似的技術位,但作爲盧恩 - 可檢查數據不知怎的,一串數字不適合我。有PHP的擴展可以處理bignum,但是由於它們是擴展,所以它是一段框架代碼,可能會被部署在各種各樣的配置上,我寧願不依賴這種存在如果可能的話。此外,上述都沒有解決如果你給PHP一個大的int它的問題默默地將其轉換爲浮動。我需要一種檢測這種情況的方法。

回答

7

如果你需要精度,你不應該使用浮動。

相反,尤其是當你想與整數工作(如果我理解正確的話),你可以嘗試用bc*功能工作:BCMath Arbitrary Precision Mathematics