Rewrote Base62 algorithm to avoid errors with very big numbers.
This commit is contained in:
parent
469391f9b6
commit
004156712b
3 changed files with 18 additions and 38 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.2410.630140
|
||||
0.2410.830201
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// IntegerBaseConverter.php
|
||||
// Created: 2024-07-31
|
||||
// Updated: 2024-08-04
|
||||
// Updated: 2024-12-22
|
||||
|
||||
namespace Index;
|
||||
|
||||
|
@ -11,7 +11,7 @@ use InvalidArgumentException;
|
|||
* Provides methods for encoding integers in different bases.
|
||||
*/
|
||||
class IntegerBaseConverter {
|
||||
private int $maxBase;
|
||||
private int $base;
|
||||
|
||||
/**
|
||||
* @param string $characterSet Specifies the provided character set, must be a string consisting out of at least two unique characters.
|
||||
|
@ -27,38 +27,27 @@ class IntegerBaseConverter {
|
|||
if(XString::countUnique($characterSet) !== $length)
|
||||
throw new InvalidArgumentException('$characterSet must contain a set of entirely unique characters');
|
||||
|
||||
$this->maxBase = $length;
|
||||
$this->base = $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a positive base10 integer to another base.
|
||||
*
|
||||
* @param int $integer The integer to encode.
|
||||
* @param int $toBase Target base, 0 for the base of the provided character set.
|
||||
* @return string The encoded data, as a string.
|
||||
*/
|
||||
public function encode(int $integer, int $toBase = 0): string {
|
||||
public function encode(int $integer): string {
|
||||
if($integer < 0)
|
||||
throw new InvalidArgumentException('$integer contains a negative value, which cannot be represented');
|
||||
if($toBase === 0)
|
||||
$toBase = $this->maxBase;
|
||||
else {
|
||||
if($toBase < 2)
|
||||
throw new InvalidArgumentException('lowest supported value for $toBase is 2');
|
||||
if($toBase > $this->maxBase)
|
||||
throw new InvalidArgumentException('specified $toBase value is greater than the amount of characters in the provided character set');
|
||||
}
|
||||
|
||||
if($integer === 0)
|
||||
return '';
|
||||
return $this->characterSet[0];
|
||||
|
||||
$output = '';
|
||||
|
||||
for($i = floor(log10($integer) / log10($toBase)); $i >= 0; --$i) {
|
||||
$exp = $toBase ** $i;
|
||||
$index = (int)floor($integer / $exp);
|
||||
$output .= $this->characterSet[$index];
|
||||
$integer -= $index * $exp;
|
||||
while($integer > 0) {
|
||||
$remainder = $integer % $this->base;
|
||||
$output = $this->characterSet[$remainder] . $output;
|
||||
$integer = intdiv($integer, $this->base);
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
@ -68,33 +57,22 @@ class IntegerBaseConverter {
|
|||
* Converts another base encoded integer to a base10 integer.
|
||||
*
|
||||
* @param string $string The encoded integer.
|
||||
* @param int $fromBase Source base, 0 for the base of the provided character set.
|
||||
* @return int|false Returns the decoded integer or false on failure.
|
||||
*/
|
||||
public function decode(string $string, int $fromBase = 0): int|false {
|
||||
if($fromBase === 0)
|
||||
$fromBase = $this->maxBase;
|
||||
else {
|
||||
if($fromBase < 2)
|
||||
throw new InvalidArgumentException('lowest supported value for $fromBase is 2');
|
||||
if($fromBase > $this->maxBase)
|
||||
throw new InvalidArgumentException('specified $fromBase value is greater than the amount of characters in the provided character set');
|
||||
}
|
||||
|
||||
public function decode(string $string): int|false {
|
||||
if($string === '')
|
||||
return 0;
|
||||
|
||||
$output = 0;
|
||||
$length = strlen($string) - 1;
|
||||
|
||||
for($i = 0; $i <= $length; ++$i) {
|
||||
for($i = 0; $i < strlen($string); ++$i) {
|
||||
$pos = strpos($this->characterSet, $string[$i]);
|
||||
if($pos === false)
|
||||
return false;
|
||||
|
||||
$output += $pos * ($fromBase ** ($length - $i));
|
||||
$output = $output * $this->base + $pos;
|
||||
}
|
||||
|
||||
return (int)$output;
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
// Base62Test.php
|
||||
// Created: 2022-01-28
|
||||
// Updated: 2024-07-31
|
||||
// Updated: 2024-12-22
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -14,16 +14,18 @@ final class Base62Test extends TestCase {
|
|||
public const TESTS = [
|
||||
['aaaaaa', 9311514030],
|
||||
['Soap', 12962613],
|
||||
['', 0],
|
||||
['0', 0],
|
||||
['1', 1],
|
||||
['kPH', 80085],
|
||||
['UC', 3510],
|
||||
['p', 25],
|
||||
['6zi', 25252],
|
||||
['1ly7vk', 1234567890],
|
||||
['15vjOLmUu1', 14739082838046309],
|
||||
];
|
||||
|
||||
public function testDecode(): void {
|
||||
$this->assertEquals(0, XNumber::fromBase62(''));
|
||||
foreach(self::TESTS as $test)
|
||||
$this->assertEquals($test[1], XNumber::fromBase62($test[0]));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue