Domanda

Ho una classe per il calcolo del checksum di LUHN per un numero. Ci vuole un numero intero come input e restituisce true o false per indicare validità o in altro modo, oppure genera un'eccezione se viene fornito un tipo di dati inappropriato come input.

Il codice è il seguente (la fonte completa è su 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);
    }
}
.

Ho anche costruito un full Test dell'unità < / a> per esercitare la classe.

Il mio ambiente di sviluppo principale è una workstation che esegue 64 bit Builds PHP 5.3 e Apache sotto il leone osx. Uso anche un laptop che esegue una build a 64 bit di Apache e PHP 5.4 anche sotto Apache. Oltre a questo ho una macchina virtuale di Ubuntu Linux che esegue 64 bit Apache e PHP 5.3. Il test dell'unità andava bene per tutti questi, come previsto.

Pensavo di poter un po 'di tempo libero durante il pranzo al lavoro (Windows 7, XAMPP, 32 bit PHP 5.3 5.3) per lavorare sul progetto che questa classe è una parte di, ma la prima cosa in cui ho corso era il fallimento dell'unità test.

Il problema è che su una build a 32 bit di PHP il numero viene catturato in silenzio per galleggiare se supera i limiti di un numero intero a 32 bit. La mia soluzione proposta è avere un caso speciale per il galleggiante. Se il tipo di input è galleggiante e il suo valore è al di fuori dell'intervallo che può essere espresso in int (php_int_min .. php_int_max) quindi lo farò Number_Format () per riportarlo in una stringa di cifre. Se è all'interno della gamma di un intero, farò un'eccezione.

Tuttavia, questo porta al proprio problema. So che più lontano si ottiene da 0 con un numero punto di galleggiamento, la risoluzione meno la risoluzione del numero (più piccola è l'incremento tra un dato numero e il successivo numero rappresentabile ottiene). Quanto lontano da 0 devi ottenere prima che diventa impossibile rappresentare la parte intera del numero prima che tu non possa rappresentare in modo affidabile la parte intera prima? (Non sono sicuro che sia davvero chiaro, quindi ad esempio, dì che il limite è 1000 prima che la risoluzione scenda sotto la differenza tra un INT e il successivo. Potrei entrare in una cifra più grande di 1000, dire 1001, ma le limitazioni di I numeri del punto galleggiante significa che finisce per essere 1001.9 e arrotondando producono 1002, il che significa che ho perso il valore in cui ero interessato).

È possibile rilevare quando la perdita di risoluzione diventerà un problema per un numero di virgola mobile?

Modifica per aggiungere : Suppongo di poter modificare l'estensione per accettare una stringa anziché un tipo numerico e quindi verificare che contiene solo cifre con una regex o qualche altra tecnica simile, ma come Luhn - I datiChibrabili sono una stringa di cifre che non si sente giusto per me, in qualche modo. Ci sono estensioni per PHP che possono gestire Bignums, ma poiché sono estensioni e questo è destinato a essere un pezzo di codice quadro che potrebbe potenzialmente essere implementato su un'ampia gamma di configurazioni, preferirei non fare affidamento sulla presenza di tale estensioni se possibile. Inoltre, nessuno dei precedenti affronta il problema che se si conferisce a PHP un grande int, lo converte silenziosamente per galleggiare. Ho bisogno di un modo di rilevare che questo è successo.

È stato utile?

Soluzione

Se hai bisogno di precisione, non dovresti usare i galleggianti.

Invece, specialmente come vuoi lavorare con interi ( se capisco correttamente ), è possibile provare a lavorare con le funzioni gmp*: GMP - GNU PRECISIONE MULTIME

Se non puoi lavorare con quell'estensione potresti ottenere alcune altre idee da

Altri suggerimenti

Se hai bisogno di precisione, non dovresti usare i galleggianti.

Invece, specialmente come vuoi lavorare con numeri interi (se ho capito correttamente) , è possibile provare a lavorare con le funzioni bc*: BCMath Arbitrary Precision Mathematics

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top