note 109660 modified in function.base-convert by danbrown

From: Date: Fri, 10 Aug 2012 16:12:43 +0000
Subject: note 109660 modified in function.base-convert by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-190002@lists.php.net to get a copy of this message
If you use base_convert to convert a large (eg. 80-bit) hexadecimal to base-36, you might observe:&#13;&#10;&#13;&#10;ABCDEF00001234567890 (hexadecimal) =&#62; 3O47RE02JZSW0KS8 (base-36) =&#62; ABCDEF00001240000000 (hexadecimal)&#13;&#10;&#13;&#10;This is normal and is due to the loss of precision on large numbers.&#13;&#10;&#13;&#10;I have written a string-based function using the built-in BC Math Extension which will overcome this and similar problems.&#13;&#10;&#13;&#10;&#60;?php&#13;&#10;&#13;&#10;function str_baseconvert($str, $frombase=10, $tobase=36) {&#13;&#10; $str = trim($str);&#13;&#10; if (intval($frombase) != 10) {&#13;&#10; $len = strlen($str);&#13;&#10; $q = 0;&#13;&#10; for ($i=0; $i&#60;$len; $i++) {&#13;&#10; $r = base_convert($str[$i], $frombase, 10);&#13;&#10; $q = bcadd(bcmul($q, $frombase), $r);&#13;&#10; }&#13;&#10; }&#13;&#10; else $q = $str;&#13;&#10; &#13;&#10; if (intval($tobase) != 10) {&#13;&#10; $s = &#39;&#39;;&#13;&#10; while (bccomp($q, &#39;0&#39;, 0) &#62; 0) {&#13;&#10; $r = intval(bcmod($q, $tobase));&#13;&#10; $s = base_convert($r, 10, $tobase) . $s;&#13;&#10; $q = bcdiv($q, $tobase, 0);&#13;&#10; }&#13;&#10; }&#13;&#10; else $s = $q;&#13;&#10; &#13;&#10; return $s;&#13;&#10;}&#13;&#10;&#13;&#10;?&#62;&#13;&#10;&#13;&#10;Typical use-cases:&#13;&#10;1. Convert a large arbitrary precision number to base-36.&#13;&#10;2. Convert a 32-char hexadecimal UUID (128-bit) to a 25-char base-36 unique key, and vice versa.&#13;&#10;&#13;&#10;Examples:&#13;&#10;&#13;&#10;&#60;?php&#13;&#10;$b16 = &#39;ABCDEF00001234567890&#39;;&#13;&#10;$b36 = str_baseconvert($b16, 16, 36);&#13;&#10;echo (&#34;$b16 (hexadecimal) = $b36 (base-36) \\n&#34;);&#13;&#10;&#13;&#10;$uuid = &#39;ABCDEF01234567890123456789ABCDEF&#39;;&#13;&#10;$ukey = str_baseconvert($uuid, 16, 36);&#13;&#10;echo (&#34;$uuid (hexadecimal) = $ukey (base-36) \\n&#34;);&#13;&#10;?&#62;&#13;&#10;&#13;&#10;ABCDEF00001234567890 (hexadecimal) = 3o47re02jzqisvio (base-36) &#13;&#10;ABCDEF01234567890123456789ABCDEF (hexadecimal) = a65xa07491kf5zyfpvbo76g33 (base-36) --was-- If you use base_convert to convert a large (eg. 80-bit) hexadecimal to base-36, you might observe: ABCDEF00001234567890 (hexadecimal) => 3O47RE02JZSW0KS8 (base-36) => ABCDEF00001240000000 (hexadecimal) This is normal and is due to the loss of precision on large numbers. I have written a string-based function using the built-in BC Math Extension which will overcome this and similar problems. <? function str_baseconvert($str, $frombase=10, $tobase=36) { $str = trim($str); if (intval($frombase) != 10) { $len = strlen($str); $q = 0; for ($i=0; $i<$len; $i++) { $r = base_convert($str[$i], $frombase, 10); $q = bcadd(bcmul($q, $frombase), $r); } } else $q = $str; if (intval($tobase) != 10) { $s = ''; while (bccomp($q, '0', 0) > 0) { $r = intval(bcmod($q, $tobase)); $s = base_convert($r, 10, $tobase) . $s; $q = bcdiv($q, $tobase, 0); } } else $s = $q; return $s; } ?> Typical use-cases: 1. Convert a large arbitrary precision number to base-36. 2. Convert a 32-char hexadecimal UUID (128-bit) to a 25-char base-36 unique key, and vice versa. Examples: <? $b16 = 'ABCDEF00001234567890'; $b36 = str_baseconvert($b16, 16, 36); echo ("$b16 (hexadecimal) = $b36 (base-36) \n"); $uuid = 'ABCDEF01234567890123456789ABCDEF'; $ukey = str_baseconvert($uuid, 16, 36); echo ("$uuid (hexadecimal) = $ukey (base-36) \n"); ?> ABCDEF00001234567890 (hexadecimal) = 3o47re02jzqisvio (base-36) ABCDEF01234567890123456789ABCDEF (hexadecimal) = a65xa07491kf5zyfpvbo76g33 (base-36) http://php.net/manual/en/function.base-convert.php

« previous php.notes (#190002) next »