Posts Tagged ‘bigint’

Share Working with Big Integers in PHP

Tuesday, August 10th, 2010

This is the start of a class I developed for working with URL shortening and doing math with large numbers such as Facebook User Ids.

There are some issues with the implementation of base convert, but if you are going between base 10 and higher it’s fine.

<?php
/**
* @author Erik Giberti
* @package Big Integer Math
*/
 
class bigint {
 
	public static function base_convert($value_in = false, $source_base = 10, $target_base = 36){
		// We use these values for our conversions
		$values = array('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','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','-','_');
		$characters = array_flip($values);
		$string_out = '';
 
		// Easy answers
		if($source_base	== $target_base){ return $value_in; }
 
		$len = strlen($value_in);
		$sum = array();
		if($source_base > $target_base){
			for($i=0;$i<$len;$i++){
				$char = substr($value_in, $len - $i - 1, 1);
				$sum[$i] = $characters[$char] * pow($source_base, $i);
			}
		} else {
			if($source_base != 10){
				$value = bigint::base_convert($value_in, $source_base, 10);
			} else {
				$value = $value_in;
			}
 
			$cnt = 0;
			while($value > 0){
				$times = $value / $target_base;
				$sum[] = bigint::mod($value, $target_base);
				$value = bigint::floor($times); // get rid of our remainder
			}
 
			for($i=count($sum);$i>0;$i--){
				$string_out .= $values[$sum[$i-1]];
			}
 
			return $string_out;
		}
 
		if($target_base == 10){ return array_sum($sum); }
		return implode($sum);
	}
 
	public static function mod($val, $mod){ return $val - floor($val/$mod) * $mod; }
 
	public static function floor($val){
		$bits = explode('.',$val);
		return $bits[0];
	}
}

Share PHP Gotcha: Bigint with sprintf()

Wednesday, December 3rd, 2008

PHP LogoToday I am working on modification of an FB application to permit installation on “pages” in addition to profiles. Facebook has switched (several months ago) to using 64bit integer values for id’s site wide. In the code I use sprintf to create stored procedure calls and couldn’t figure out why the values the the database weren’t matching up with my expectations… the following code would output 536035818 instead of the much larger 30600806890 value I expected. Clearly this is a 32bit vs 64bit.

$big_int = 30600806890;
$format = "%d";
$new_string = sprintf($format, $big_int);
print $new_string;

Since updating to a fully 64 bit platform and so on really isn’t an option, I needed a work around. I composed a quick test for my value and ran it. The test as you can see, it provides output for each of the valid substitution types in sprintf.

$big_int = 30600806890;
$type = array("%b","%c","%d","%e","%u","%f","%F","%o","%s","%x","%X");
for($i=0;$i<count($type);$i++){
        print $type[$i] . ": " . sprintf($type[$i], $big_int) . "\n";
}

This results with the list below. Obviously floating point numbers and strings are the only way to handle these bigint values. A simple drop in value is of course to swap %s for %d as needed, but you lose some type catching which may cause security issues. Instead, I recommend using %0.0f which will suppress the decimal portion – keeping the int an int – while keeping the numeric type checking intact.

%b: 11111111100110100000111101010
%c: ?
%d: 536035818
%e: 3.06008e+10
%u: 536035818
%f: 30600806890.000000
%F: 30600806890.000000
%o: 3774640752
%s: 30600806890
%x: 1ff341ea
%X: 1FF341EA
© 1998-2008 AF-Design, All rights reserved.