PHP - tam bölerek iki dizi neden bir hatayı düzeltmek yardımcı

3 Cevap php

Ben youtube tarzı URL için bir kod parçası ile çalışıyoruz ama ben bir hata bulduk ve ben birisi bana bunu düzeltmek için en verimli yol gösterebilir umuyorum.

function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
    static $passcache;
        if(empty($passcache))
                $passcache = array();

    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    if (!empty($passKey)) {
        // Although this function's purpose is to just make the
        // ID short - and not so much secure,
        // with this patch by Simon Franz (http://blog.snaky.org/)
        // you can optionally supply a password to make it harder
        // to calculate the corresponding numeric ID

                if(isset($passcache[$passKey]))
                        $index = $passcache[$passKey];
                else {
                        if(strlen($passhash = hash('sha256',$passKey)) < strlen($index))
                                $passhash = hash('sha512',$passKey);

                        $p = str_split($passhash);

                        array_multisort($p, SORT_DESC, $i);
                        $index = implode($i);
                        $passcache = $index;
                }
    }

    $base = strlen($index);

    if ($to_num) {
        // Digital number <<-- alphabet letter code
        $in = strrev($in);
        $out = 0;
        $len = strlen($in) - 1;
        for ($t = 0; $t <= $len; $t++) {
            $bcpow = bcpow($base, $len - $t);
            $out += strpos($index, $in[$t]) * $bcpow;
        }

        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $out -= pow($base, $pad_up);
            }
        }
    } else {
        // Digital number -->> alphabet letter code
        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $in += pow($base, $pad_up);
            }
        }

        $out = "";
        for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
                $bcp = bcpow($base, $t);
            $a = floor($in / $bcp);
            $out .= $index[$a];
            $in -= $a *  $bcp;
        }
        $out = strrev($out); // reverse
    }

    return $out;
}

Bu üç güç benim temel olarak bir tek sayı 238.328 kodlayan sadece hatadır. Sonuç olarak tam olarak böler ve çünkü 'zemin' kullanım fark edilmeden gider ve komut yoksa 62 karakter eklemek için çalışır ve sadece dört yerine üç karakter kod üretir ... Böylece 'aa' sonucudur yerine 'AAAB' den.

İşte kod sorunun parçası olduğunu:

        for ($t = floor(log10($in) / log10($base)); $t >= 0; $t--) {
                $bcp = bcpow($base, $t);
            $a = floor($in / $bcp);
            $out .= $index[$a];
            $in -= $a *  $bcp;

Ve yapmak bile kolay burada hata almak için çağrı

echo alphaID(238328);

Credit: Orginally Kevin Vanzonneveld tarafından yazılmış: kevin nokta Simon Franz tarafından modifiye dot net, vanzonneveld: blog dot snaky dot org ve Stackoverflows çok kendi mattbasta tarafından optimize

3 Cevap

Bu bir temizleyici olmasına rağmen ilk olarak başka bir cevap ekleme de çalışıyor.

Ben M.Ö. Matematik fonksiyonların kurtuldum. Eğer gerçekten büyük tamsayılar ile çalışmak için gidiyoruz, bu çalışmayabilir. Aksi takdirde, bu kadar temiz bir çözümdür:

function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
    static $passcache;
        if(empty($passcache))
                $passcache = array();

    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    if (!empty($passKey)) {
        // Although this function's purpose is to just make the
        // ID short - and not so much secure,
        // with this patch by Simon Franz (http://blog.snaky.org/)
        // you can optionally supply a password to make it harder
        // to calculate the corresponding numeric ID

                if(isset($passcache[$passKey]))
                       $index = $passcache[$passKey];
                else {
                        if(strlen($passhash = hash('sha256',$passKey)) < strlen($index))
                                $passhash = hash('sha512',$passKey);

                        $p = str_split($passhash);

                        array_multisort($p, SORT_DESC, $i);
                        $index = implode($i);
                        $passcache = $index;
                }
    }

    $base = strlen($index);

    if ($to_num) {
        // Digital number <<-- alphabet letter code

        // A conversion from base $base to base 10

        $out = 0;           // End number
        $shift = 1;         // Starting shift
        $len = strlen($in); // Length of string

        for ($t = 0; $t < $len; $t++) 
        {
            $out += strpos($index, $in[$t]) * $shift; // $out is a number form alphabet * base^shift
            $shift *= $base;  // increase shift
        }       


        if (is_numeric($pad_up)) {
           $pad_up--;
           if ($pad_up > 0) {
               $out -= pow($base, $pad_up);
            }
        }
    } else {
        // Digital number -->> alphabet letter code
        if (is_numeric($pad_up)) {
            $pad_up--;
            if ($pad_up > 0) {
                $in += pow($base, $pad_up);
            }
        }

        $out = "";

        // A simple conversion from base 10 to base $base

        while ($in > 0)
        {
            $remainder = $in % $base;
            $in = intval(($in-$remainder)/$base);

            $out .= $index[$remainder];
        }

    }

    return $out;
}

The code is cleaner, and should be faster as well. Now it is much easier to see that this is only conversion from base 10 to base $base (62?) and vica-versa. It does not involve floating point division, thus it does not have the bug mentioned above.

Eğer böylece çoğaltan Büyük tamsayıları, ve gerekiyorsa, bu bazı parlak düşünce ile de bu şekilde uygulanabilir.

Eğer Büyük tamsayıları ihtiyacınız dediği gibi, BC Matematik eklendi

function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
   static $passcache;
       if(empty($passcache))
               $passcache = array();

   $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
   $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
   if (!empty($passKey)) {
       // Although this function's purpose is to just make the
       // ID short - and not so much secure,
       // with this patch by Simon Franz (http://blog.snaky.org/)
       // you can optionally supply a password to make it harder
       // to calculate the corresponding numeric ID

               if(isset($passcache[$passKey]))
                      $index = $passcache[$passKey];
               else {
                       if(strlen($passhash = hash('sha256',$passKey)) < strlen($index))
                               $passhash = hash('sha512',$passKey);

                       $p = str_split($passhash);

                       array_multisort($p, SORT_DESC, $i);
                       $index = implode($i);
                       $passcache = $index;
               }
   }

   $base = strlen($index);

   if ($to_num) {
       // Digital number <<-- alphabet letter code

       // A conversion from base $base to base 10

       $out = '0';           // End number
       $shift = 1;         // Starting shift
       $len = strlen($in); // Length of string

       for ($t = 0; $t < $len; $t++) 
       {
           $out = bcadd($out, bcmul(strpos($index, $in[$t]),$shift)); // $out is a number from alphabet * base^shift
           $shift = bcmul($shift, $base);  // increase shift
       }       


       if (is_numeric($pad_up)) {
          $pad_up--;
          if ($pad_up > 0) {
              $out -= pow($base, $pad_up);
           }
       }
   } else {
       // Digital number -->> alphabet letter code
       if (is_numeric($pad_up)) {
           $pad_up--;
           if ($pad_up > 0) {
               $in += pow($base, $pad_up);
            }
        }

        $out = "";

        // A simple conversion from base 10 to base $base

        while ($in > '0') // We're treating integer as a string, so BC math works
       {
            $remainder = bcmod($in,$base);
            $in = bcdiv($in, $base);

            $out .= $index[$remainder];
        }

    }

    return $out;
}

Buyrun:

function preciseDivision($x,$y)
{
    // Correct floor's failures by adding a bit of overhead
    $epsilon = 0.00000001;
    return floor(($x/$y) + $epsilon);
}
function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
    static $passcache;
    if(empty($passcache))
            $passcache = array();

    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $i = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    if (!empty($passKey)) {
       // Although this function's purpose is to just make the
       // ID short - and not so much secure,
       // with this patch by Simon Franz (http://blog.snaky.org/)
       // you can optionally supply a password to make it harder
       // to calculate the corresponding numeric ID

               if(isset($passcache[$passKey]))
                       $index = $passcache[$passKey];
               else {
                       if(strlen($passhash = hash('sha256',$passKey)) < strlen($index))
                               $passhash = hash('sha512',$passKey);

                       $p = str_split($passhash);

                       array_multisort($p, SORT_DESC, $i);
                       $index = implode($i);
                       $passcache = $index;
               }
   }

   $base = strlen($index);

   if ($to_num) {
       // Digital number <<-- alphabet letter code
       $in = strrev($in);
       $out = 0;
       $len = strlen($in) - 1;
       for ($t = 0; $t <= $len; $t++) {
           $bcpow = bcpow($base, $len - $t);
           $out += strpos($index, $in[$t]) * $bcpow;
       }

       if (is_numeric($pad_up)) {
           $pad_up--;
           if ($pad_up > 0) {
               $out -= pow($base, $pad_up);
           }
       }
   } else {
       // Digital number -->> alphabet letter code
       if (is_numeric($pad_up)) {
           $pad_up--;
           if ($pad_up > 0) {
               $in += pow($base, $pad_up);
           }
       }

       $out = "";

       for ($t = preciseDivision(log10($in),log10($base)); $t >= 0; $t--) {

           $bcp = bcpow($base, $t);

           $a = preciseDivision($in, $bcp);
           $out .= $index[$a];
           $in -= $a *  $bcp;
       }
       $out = strrev($out); // reverse
   }

   return $out;
}

Burada sorun zemin değildi, ama kayan nokta hassas. Bölümü 2.99999999 sonuçlandı ve zemin (2.999999) 2 eşittir, değil 3. Bu olur çünkü kayan nokta değişkenler sınırlı boyutudur.

Işe yaramadı bu yüzden.

Bu aracılığıyla almak için otomatik olarak bölünme çok küçük bir değer katan bir fonksiyon preciseDivision, yazdı.

Ve ben hala bu url karma soruna temizleyici çözüm orada var gerektiğine inanıyoruz. Ben ne yapabilirim görürsünüz.

my answer başı olarak diğer soruya, log($in, $base) ile log10($in) / log10($base) değiştirmeyi deneyin.

Bu kayan noktalı sayı olarak iki logaritma sonuçlarını bölünmesi ile ilgili yanlışlıklar önler ve size doğru sonucu verir.