2012-05-20 5 views
3

Luhn 체크섬 계산을위한 클래스가 있습니다. integer를 입력으로 취하고 유효성 또는 기타를 나타내는 true 또는 false를 반환하거나 부적절한 데이터 유형이 입력으로 주어지면 예외를 throw합니다. 나는 또한 클래스를 행사 전체 unit test를 구축32 비트 PHP로 큰 int에 대처하기

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

:

코드는 다음과 같이 (전체 소스 GitHub에)입니다.

내 주요 개발 환경은 OSX Lion에서 PHP 5.3과 Apache를 64 비트 빌드하는 워크 스테이션입니다. 또한 64 비트 아파치와 PHP 5.4를 아파치에서 실행하는 노트북을 사용합니다. 이뿐 아니라 64 비트 아파치와 PHP 5.3을 실행하는 우분투 리눅스 가상 머신을 가지고 있습니다. 단위 테스트는 예상대로이 모든 것에 적합했습니다.

나는이 클래스가 속해있는 프로젝트 작업을 위해 일하는 점심 시간 (Windows 7, XAMPP, 32 비트 PHP 5.3)에서 여유 시간을 가질 수 있다고 생각했지만, 단위 테스트.

문제는 PHP의 32 비트 빌드에서 32 비트 정수의 제한을 초과하면 자동으로 숫자가 부동으로 변환된다는 것입니다. 내 제안 된 솔루션은 float에 대한 특별한 경우입니다. 입력 유형이 float이고 해당 값이 int로 표현할 수있는 범위를 벗어난 경우 (PHP_INT_MIN .. PHP_INT_MAX) number_format()을 사용하여 숫자 문자열로 다시 가져옵니다. 정수 범위 내에 있으면 예외를 throw합니다.

그러나 이것은 자체 문제점을 야기합니다. 부동 소수점 숫자가 0에서 멀어 질수록 더 적은 수의 해상도 (주어진 숫자와 다음 표현 가능한 숫자 사이의 증가분이 작아짐)를 알 수 있습니다. 정수 부분을 더 이상 신뢰할 수 없게 표시하기 전에 0부터 얼마나 멀리 떨어져 있어야만 숫자의 정수 부분을 나타낼 수 없게됩니까? (나는 그것이 정말로 명확한 지 잘 모르겠다. 예를 들어, 한계가 1000이고, 해상도가 int와 다음의 차이보다 작아지기 전이라면, 1000보다 큰 숫자, 즉 1001을 입력 할 수 있지만 한계는 부동 소수점 숫자는 1001.9라는 것을 의미하고 1002를 반올림하면 내가 관심있는 가치를 잃어버린 것입니다.

해상도 손실이 부동 소수점에 문제가 될 때를 감지 할 수 있습니까? Luhn - 체크 가능한 데이터가 그대로 내가 대신 숫자 형식의 문자열을 받아 다음 정규식 또는 다른 유사한 기술 만 숫자가 포함되어 있는지 확인하기 위해 확장을 수정할 수 있지만 가정 :

편집을 추가하려면 어떻게 든 나에게 맞는 느낌이 들지 않는 자릿수. bignums를 처리 할 수있는 PHP 용 확장 기능이 있지만, 확장 기능이며 광범위한 구성에서 잠재적으로 배포 될 수있는 프레임 워크 코드로 사용되기 때문에 이러한 기능의 존재에 의존하지 않을 것입니다. 확장이 가능하다면. 게다가 위의 어느 것도 PHP에 큰 int를 제공하면 자동으로 float로 변환되지 않는다는 문제를 해결하지 못했습니다. 이런 일이 발생했는지 감지 할 방법이 필요합니다.

답변

7

정밀도가 필요한 경우에는 수레를 사용하지 않아야합니다.

대신, 당신은 (내가 제대로 이해한다면) 정수 으로을 작업 할 특히, 당신은 bc* 기능 작업을 시도 할 수 있습니다 : 당신이 정밀도를 필요로하는 경우, 당신은 수레를 사용하지 말아야 BCMath Arbitrary Precision Mathematics