How to ceil, floor and round bcmath numbers? - php
I need to mimic the exact functionality of the ceil(), floor() and round() functions on bcmath numbers, I've already found a very similar question but unfortunately the answer provided isn't good enough for me since it lacks support for negative numbers and the precision argument for the round() function is missing.
I was wondering if anyone can come up with a rather short and elegant solution to this problem.
All input is appreciated, thanks!
After a night lost trying to solve this problem I believe I've found a rather simple solution, here it is:
function bcceil($number)
{
if (strpos($number, '.') !== false) {
if (preg_match("~\.[0]+$~", $number)) {
return bcround($number, 0);
}
if ($number[0] != '-') {
return bcadd($number, 1, 0);
}
return bcsub($number, 0, 0);
}
return $number;
}
function bcfloor($number)
{
if (strpos($number, '.') !== false) {
if (preg_match("~\.[0]+$~", $number)) {
return bcround($number, 0);
}
if ($number[0] != '-') {
return bcadd($number, 0, 0);
}
return bcsub($number, 1, 0);
}
return $number;
}
function bcround($number, $precision = 0)
{
if (strpos($number, '.') !== false) {
if ($number[0] != '-') {
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return $number;
}
I think I didn't miss anything, if someone can spot any bug please let me know. Here are some tests:
assert(bcceil('4') == ceil('4')); // true
assert(bcceil('4.3') == ceil('4.3')); // true
assert(bcceil('9.999') == ceil('9.999')); // true
assert(bcceil('-3.14') == ceil('-3.14')); // true
assert(bcfloor('4') == floor('4')); // true
assert(bcfloor('4.3') == floor('4.3')); // true
assert(bcfloor('9.999') == floor('9.999')); // true
assert(bcfloor('-3.14') == floor('-3.14')); // true
assert(bcround('3', 0) == number_format('3', 0)); // true
assert(bcround('3.4', 0) == number_format('3.4', 0)); // true
assert(bcround('3.5', 0) == number_format('3.5', 0)); // true
assert(bcround('3.6', 0) == number_format('3.6', 0)); // true
assert(bcround('1.95583', 2) == number_format('1.95583', 2)); // true
assert(bcround('5.045', 2) == number_format('5.045', 2)); // true
assert(bcround('5.055', 2) == number_format('5.055', 2)); // true
assert(bcround('9.999', 2) == number_format('9.999', 2)); // true
function bcnegative($n)
{
return strpos($n, '-') === 0; // Is the number less than 0?
}
function bcceil($n)
{
return bcnegative($n) ? (($v = bcfloor(substr($n, 1))) ? "-$v" : $v)
: bcadd(strtok($n, '.'), strtok('.') != 0);
}
function bcfloor($n)
{
return bcnegative($n) ? '-' . bcceil(substr($n, 1)) : strtok($n, '.');
}
function bcround($n, $p = 0)
{
$e = bcpow(10, $p + 1);
return bcdiv(bcadd(bcmul($n, $e, 0), bcnegative($n) ? -5 : 5), $e, $p);
}
Here's ones that support negative numbers and precision argument for rounding.
function bcceil($val) {
if (($pos = strpos($val, '.')) !== false) {
if ($val[$pos+1] != 0 && $val[0] != '-')
return bcadd(substr($val, 0, $pos), 1, 0);
else
return substr($val, 0, $pos);
}
return $val;
}
function bcfloor($val) {
if (($pos = strpos($val, '.')) !== false) {
if ($val[$pos+1] != 0 && $val[0] == '-')
return bcsub(substr($val, 0, $pos), 1, 0);
else
return substr($val, 0, $pos);
}
return $val;
}
function bcround($val, $precision = 0) {
if (($pos = strpos($val, '.')) !== false) {
if ($precision > 0) {
$int = substr($val, 0, $pos);
$pos2 = ++$pos+$precision;
if ($pos2 < strlen($val)) {
$val2 = sprintf('%s.%s', substr($val, $pos, $pos2-$pos), substr($val, $pos2));
$val2 = $val2[0] >= 5 ? bcceil($val2) : bcfloor($val2);
if (strlen($val2) > $precision)
return bcadd($int, $val[0] == '-' ? -1 : 1, 0);
else
return sprintf('%s.%s', $int, rtrim($val2, '0'));
}
return $val;
} else {
if ($val[$pos+1] >= 5)
return ($val[0] == '-' ? bcfloor($val) : bcceil($val));
else
return ($val[0] == '-' ? bcceil($val) : bcfloor($val));
}
}
return $val;
}
I chose the Alix Axel's variant for rounding as it is the fastest since it only uses addition and subtraction, not multiplication and division. To round with negative precision at the beginnig I used standard function:
sprintf('%.0F', round($result, $operand_value))
But I faced the problem described here. So I extended this variant for negative precision:
function bcround($number, $precision)
{
if($precision >= 0)
{
if (strpos($number, '.') !== false)
{
if ($number[0] != '-')
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return $number;
}
else
{
$mod = bcmod($number, bcpow(10, -$precision));
$sub = bcsub($number, $mod);
if($mod[0] != '-')
{
$add = $mod[0] >= 5 ? bcpow(10, strlen($mod)) : 0;
}
else
{
$add = $mod[1] >= 5 ? '-'.bcpow(10, strlen($mod)-1) : 0;
}
return bcadd($sub, $add);
}
}
A more elegant and shorter option through recursion:
function bcround($number, $precision)
{
if($precision >= 0)
{
if (strpos($number, '.') !== false)
{
if ($number[0] != '-')
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
}
return $number;
}
else
{
$pow = bcpow(10, -$precision);
return bcmul(bcround(bcdiv($number, $pow, -$precision), 0), $pow);
}
}
But it is slower because it uses two operations (division and multiplication) versus one operation of finding the remainder of the division (mod) in the first case. Speed tests have confirmed this:
First variant. Total iterations:10000. Duration: 0.24502515792847 seconds.
Second variant. Total iterations:10000. Duration: 0.35303497314453 seconds.
Only use bcmath functions to do that:
function bcceil($number, $precision = 0) {
$delta = bcdiv('9', bcpow(10, $precision + 1), $precision + 1);
$number = bcadd($number, $delta, $precision + 1);
$number = bcadd($number, '0', $precision);
return $number;
}
function bcfloor($number, $precision = 0) {
$number = bcadd($number, '0', $precision);
return $number;
}
For test:
$numbers = [
'1', '1.1', '1.4', '1.5', '1.9',
'1.01', '1.09', '1.10', '1.19', '1.90', '1.99',
'2'
];
foreach ($numbers as $n) {
printf("%s (ceil)--> %s\n", $n, bcceil($n, 1));
}
printf("\n");
foreach ($numbers as $n) {
printf("%s (floor)--> %s\n", $n, bcfloor($n, 1));
}
And the test results:
1 (ceil)--> 1.0
1.1 (ceil)--> 1.1
1.4 (ceil)--> 1.4
1.5 (ceil)--> 1.5
1.9 (ceil)--> 1.9
1.01 (ceil)--> 1.1
1.09 (ceil)--> 1.1
1.10 (ceil)--> 1.1
1.19 (ceil)--> 1.2
1.90 (ceil)--> 1.9
1.99 (ceil)--> 2.0
2 (ceil)--> 2.0
1 (floor)--> 1.0
1.1 (floor)--> 1.1
1.4 (floor)--> 1.4
1.5 (floor)--> 1.5
1.9 (floor)--> 1.9
1.01 (floor)--> 1.0
1.09 (floor)--> 1.0
1.10 (floor)--> 1.1
1.19 (floor)--> 1.1
1.90 (floor)--> 1.9
1.99 (floor)--> 1.9
2 (floor)--> 2.0
function getBcRound($number, $precision = 0)
{
$precision = ($precision < 0)
? 0
: (int) $precision;
if (strcmp(bcadd($number, '0', $precision), bcadd($number, '0', $precision+1)) == 0) {
return bcadd($number, '0', $precision);
}
if (getBcPresion($number) - $precision > 1) {
$number = getBcRound($number, $precision + 1);
}
$t = '0.' . str_repeat('0', $precision) . '5';
return $number < 0
? bcsub($number, $t, $precision)
: bcadd($number, $t, $precision);
}
function getBcPresion($number) {
$dotPosition = strpos($number, '.');
if ($dotPosition === false) {
return 0;
}
return strlen($number) - strpos($number, '.') - 1;
}
var_dump(getBcRound('3', 0) == number_format('3', 0));
var_dump(getBcRound('3.4', 0) == number_format('3.4', 0));
var_dump(getBcRound('3.56', 0) == number_format('3.6', 0));
var_dump(getBcRound('1.95583', 2) == number_format('1.95583', 2));
var_dump(getBcRound('5.045', 2) == number_format('5.045', 2));
var_dump(getBcRound('5.055', 2) == number_format('5.055', 2));
var_dump(getBcRound('9.999', 2) == number_format('9.999', 2));
var_dump(getBcRound('5.0445', 5) == number_format('5.044500', 5));
var_dump(getBcRound('5.0445', 4) == number_format('5.04450', 4));
var_dump(getBcRound('5.0445', 3) == number_format('5.0445', 3));
var_dump(getBcRound('5.0445', 2) == number_format('5.045', 2));
var_dump(getBcRound('5.0445', 1) == number_format('5.05', 1));
var_dump(getBcRound('5.0445', 0) == number_format('5.0', 0));//
var_dump(getBcRound('5.04455', 2) == number_format('5.045', 2));
var_dump(getBcRound('99.999', 2) == number_format('100.000', 2));
var_dump(getBcRound('99.999') == number_format('99.999', 0));
var_dump(getBcRound('99.999', 'a') == number_format('99.999', 0));
var_dump(getBcRound('99.999', -1.5) == number_format('99.999', 0));
var_dump(getBcRound('-0.00001', 2) == number_format('-0.000', 2));
var_dump(getBcRound('-0.0000', 2) == number_format('0', 2));
var_dump(getBcRound('-4.44455', 2) == number_format('-4.445', 2));
var_dump(getBcRound('-4.44555', 0) == number_format('-4.5', 0));
var_dump(getBcRound('-4.444444444444444444444444444444444444444444445', 0) == number_format('-4.5', 0));
Related
covert the output of php disk_total_space() in terms of GB
i have this code snippet from my project where it gets the free space in my specified disk so here it is $ds = disk_total_space(substr(base_path(), 0, 2)); $fs = disk_free_space(substr(base_path(), 0, 2)); so what i needed to do it return the value in terms of GB all the time any ideas on ow i can do this? thanks so much in advance! update i have found this code where it coverts the byte into different format if ($ds >= 1073741824) { $ds = number_format($ds / 1073741824, 2) . ' GB'; } elseif ($ds >= 1048576) { $ds = number_format($ds / 1048576, 2) . ' MB'; } elseif ($ds >= 1024) { $ds = number_format($ds / 1024, 2) . ' KB'; } elseif ($ds > 1) { $ds = $ds . ' B'; } elseif ($ds == 1) { $ds = $ds . ' B'; } else { $ds = '0 size'; } any idea on how i can only make it into GB only?
i used this function :) private function convGB($bytes, $unit = "", $decimals = 2) { $units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4, 'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8); $value = 0; if ($bytes > 0) { if (!array_key_exists($unit, $units)) { $pow = floor(log($bytes)/log(1024)); $unit = array_search($pow, $units); } $value = ($bytes/pow(1024,floor($units[$unit]))); } if (!is_numeric($decimals) || $decimals < 0) { $decimals = 2; } return sprintf('%.' . $decimals . 'f '.$unit, $value); } calling it like convGB(*bytes in here*);
$bytes = disk_total_space("/"); # 'B', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB'; $base = 1024; echo("<br />" . number_format($bytes / ceil($base ** 3), '2', '.', ' ') . "GB"); # We're assuming that 3 is GB (position 3 of the array)
human readable file size
function humanFileSize($size) { if ($size >= 1073741824) { $fileSize = round($size / 1024 / 1024 / 1024,1) . 'GB'; } elseif ($size >= 1048576) { $fileSize = round($size / 1024 / 1024,1) . 'MB'; } elseif($size >= 1024) { $fileSize = round($size / 1024,1) . 'KB'; } else { $fileSize = $size . ' bytes'; } return $fileSize; } ... works great except: I can't manually choose in what format I need to display, say i want to show in MB only whatever the file size is. Currently if its in the GB range, it would only show in GB. Also, how do I limit the decimal to 2?
Try something like this: function humanFileSize($size,$unit="") { if( (!$unit && $size >= 1<<30) || $unit == "GB") return number_format($size/(1<<30),2)."GB"; if( (!$unit && $size >= 1<<20) || $unit == "MB") return number_format($size/(1<<20),2)."MB"; if( (!$unit && $size >= 1<<10) || $unit == "KB") return number_format($size/(1<<10),2)."KB"; return number_format($size)." bytes"; }
There is great example by Jeffrey Sambells: function human_filesize($bytes, $dec = 2): string { $size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $factor = floor((strlen($bytes) - 1) / 3); if ($factor == 0) $dec = 0; return sprintf("%.{$dec}f %s", $bytes / (1024 ** $factor), $size[$factor]); } echo human_filesize(filesize('example.zip'));
I'm using this method: function byteConvert($bytes) { if ($bytes == 0) return "0.00 B"; $s = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); $e = floor(log($bytes, 1024)); return round($bytes/pow(1024, $e), 2).$s[$e]; } works great in o(1).
A pretty short 3 lines method that I use (1024 = 1KB) and supports from KB to YB is the following one: <?php /** * Converts a long string of bytes into a readable format e.g KB, MB, GB, TB, YB * * #param {Int} num The number of bytes. */ function readableBytes($bytes) { $i = floor(log($bytes) / log(1024)); $sizes = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); return sprintf('%.02F', $bytes / pow(1024, $i)) * 1 . ' ' . $sizes[$i]; } // "1000 B" echo readableBytes(1000); // "9.42 MB" echo readableBytes(9874321); // "9.31 GB" // The number of bytes as a string is accepted as well echo readableBytes("10000000000"); // "648.37 TB" echo readableBytes(712893712304234); // "5.52 PB" echo readableBytes(6212893712323224); More info about these methods on this article.
To expand on Vaidas' answer, here's how you should do it to account for the new IEC standards: function human_readable_bytes($bytes, $decimals = 2, $system = 'binary') { $mod = ($system === 'binary') ? 1024 : 1000; $units = array( 'binary' => array( 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', ), 'metric' => array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', ), ); $factor = floor((strlen($bytes) - 1) / 3); return sprintf("%.{$decimals}f%s", $bytes / pow($mod, $factor), $units[$system][$factor]); } Technically, according to the specifications for storage devices and such you should use the metric system as default (that's why Google converter shows kB -> MB as mod 1000 instead of 1024).
Here's my custom function for displaying human readable file size: function getHumanReadableSize($bytes) { if ($bytes > 0) { $base = floor(log($bytes) / log(1024)); $units = array("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); //units of measurement return number_format(($bytes / pow(1024, floor($base))), 3) . " $units[$base]"; } else return "0 bytes"; }
function bytesToHuman($bytes) { $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; for ($i = 0; $bytes > 1024; $i++) $bytes /= 1024; return round($bytes, 2) . ' ' . $units[$i]; } Credit: https://laracasts.com/discuss/channels/laravel/human-readable-file-size-and-time?page=1#reply=115796
You can modify your function to fullfil both your need to force a unit if given and adjust the precision. function humanFileSize($size, $precision = 1, $show = "") { $b = $size; $kb = round($size / 1024, $precision); $mb = round($kb / 1024, $precision); $gb = round($mb / 1024, $precision); if($kb == 0 || $show == "B") { return $b . " bytes"; } else if($mb == 0 || $show == "KB") { return $kb . "KB"; } else if($gb == 0 || $show == "MB") { return $mb . "MB"; } else { return $gb . "GB"; } } //Test with different values echo humanFileSize(1038) . "<br />"; echo humanFileSize(103053, 0) . "<br />"; echo humanFileSize(103053) . "<br />"; echo humanFileSize(1030544553) . "<br />"; echo humanFileSize(1030534053405, 2, "GB") . "<br />"; ;
function getHumanReadableSize($size, $unit = null, $decemals = 2) { $byteUnits = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; if (!is_null($unit) && !in_array($unit, $byteUnits)) { $unit = null; } $extent = 1; foreach ($byteUnits as $rank) { if ((is_null($unit) && ($size < $extent <<= 10)) || ($rank == $unit)) { break; } } return number_format($size / ($extent >> 10), $decemals) . $rank; } If php version below 5.4 use $byteUnits = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
I wanted a function that returned filesizes like Windows does, and surprisingly I could find none at all. Even worse, some here and elsewhere are broken in that they assume 1KB = 1000B. So I coded one! Plus two helper functions. Here they are: // Returns a size in a human-readable form from a byte count. function humanSize($bytes) { if ($bytes < 1024) return "$bytes Bytes"; $units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; foreach ($units as $i => $unit) { // The reason for this threshold is to avoid e.g., "1000 KB", // instead jumping from e.g., "999 KB" to "0.97 MB". $multiplier = pow(1024, $i + 1); $threshold = $multiplier * 1000; if ($bytes < $threshold) { $size = formatToMinimumDigits($bytes / $multiplier, false); return "$size $unit"; } } } // Efficiently calculates how many digits the integer portion of a number has. function digits($number) { // Yes, I could convert to string and count the characters, // but this is faster and cooler. $log = log10($number); if ($log < 0) return 1; return floor($log) + 1; } // Formats a number to a minimum amount of digits. // In other words, makes sure that a number has at least $digits on it, even if // that means introducing redundant decimal zeroes at the end, or rounding the // ones present exceeding the $digits count when combined with the integers. // For example: // formatToMinimumDigits(10) // 10.0 // formatToMinimumDigits(1.1) // 1.10 // formatToMinimumDigits(12.34) // 12.3 // formatToMinimumDigits(1.234) // 1.23 // formatToMinimumDigits(1.203) // 1.20 // formatToMinimumDigits(123.4) // 123 // formatToMinimumDigits(100) // 100 // formatToMinimumDigits(1000) // 1000 // formatToMinimumDigits(1) // 1.00 // formatToMinimumDigits(1.002) // 1.00 // formatToMinimumDigits(1.005) // 1.01 // formatToMinimumDigits(1.005, false) // 1.00 // This is primarily useful for generating human-friendly numbers. function formatToMinimumDigits($value, $round = true, $digits = 3) { $integers = floor($value); $decimalsNeeded = $digits - digits($integers); if ($decimalsNeeded < 1) { return $integers; } else { if ($round) { // This relies on implicit type casting of float to string. $parts = explode('.', round($value, $decimalsNeeded)); // We re-declare the integers because they may change // after we round the number. $integers = $parts[0]; } else { // Again, implicit type cast to string. $parts = explode('.', $value); } // And because of the implicit type cast, we must guard against // 1.00 becoming 1, thus not exploding the second half of it. $decimals = isset($parts[1]) ? $parts[1] : '0'; $joined = "$integers.$decimals".str_repeat('0', $digits); return substr($joined, 0, $digits + 1); } } Usage is as simple as humanSize(123456789).
This is how I use, it's clean and simple. Also can be used like this: public function getHumanReadableFilesize(int $bytes, int $dec = 2): string { $size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; $factor = floor((strlen($bytes) - 1) / 3); return sprintf("%.{$dec}f %s", ($bytes / (1024 ** $factor)), $size[$factor]); } Thanks #Márton Tamás for suggestion to add like comment.
Here is a working function managing till Yottabyte: function DisplayFileSize($size, $unit = false, $precision = 2){ $b = $size; $kb = round($size / 1024, $precision); $mb = round($kb / 1024, $precision); $gb = round($mb / 1024, $precision); $tb = round($gb / 1024, $precision); $pb = round($tb / 1024, $precision); $eb = round($pb / 1024, $precision); $zb = round($eb / 1024, $precision); $yb = round($zb / 1024, $precision); if((!$unit && floor($kb) == 0) || $unit == "b") { return array("value" => FormatNumber($b), "unit" => "bytes"); } else if((!$unit && floor($mb) == 0) || $unit == "kb") { return array("value" => FormatNumber($kb, 2), "unit" => "Kb"); } else if((!$unit && floor($gb) == 0) || $unit == "mb") { return array("value" => FormatNumber($mb, 2), "unit" => "Mb"); } else if((!$unit && floor($tb) == 0) || $unit == "gb") { return array("value" => FormatNumber($gb, 2), "unit" => "Gb"); } else if((!$unit && floor($pb) == 0) || $unit == "tb") { return array("value" => FormatNumber($tb, 2), "unit" => "Tb"); } else if((!$unit && floor($eb) == 0) || $unit == "pb") { return array("value" => FormatNumber($pb, 2), "unit" => "Pb"); } else if((!$unit && floor($zb) == 0) || $unit == "eb") { return array("value" => FormatNumber($eb, 2), "unit" => "Eb"); } else if((!$unit && floor($yb) == 0) || $unit == "zb") { return array("value" => FormatNumber($zb, 2), "unit" => "Zb"); } else { return array("value" => FormatNumber($yb, 2), "unit" => "Yb"); } }
issue in printing output
i am using below code to print the id3 tags of MP2 files but the output is coming in this form Array ( [FileName] => 4.mp3 [TAG] => ID3 [Version] => 3.0 [Title] => &Bahut Khubsurat Ghazal (mr-Jatt.Com) [Album] => 1Loverz Choice (A Khubsurat Ghazal) (www.mzc.in) [Author] => DJ Badboy (mr-Jatt.Com) [Track] => (www.mzc.in) ) but i want plain output like this FileName 4.mp3 Title Bahut Khubsurat Ghazal (mr-Jatt.Com) Album 1Loverz Choice (A Khubsurat Ghazal) (www.mzc.in) Author DJ Badboy (mr-Jatt.Com) Track (www.mzc.in) my code is print_r(tagReader("4.mp3")); // ------------------------------ function tagReader($file) { $id3v23 = array("TIT2","TALB","TPE1","TRCK","TDRC","TLEN","USLT"); $id3v22 = array("TT2","TAL","TP1","TRK","TYE","TLE","ULT"); $fsize = filesize($file); $fd = fopen($file, "r"); $tag = fread($fd, $fsize); $tmp = ""; fclose($fd); if (substr($tag, 0, 3) == "ID3") { $result['FileName'] = $file; $result['TAG'] = substr($tag, 0, 3); $result['Version'] = hexdec(bin2hex(substr($tag, 3, 1))) . "." . hexdec(bin2hex(substr($tag, 4, 1))); } if ($result['Version'] == "4.0" || $result['Version'] == "3.0") { for($i = 0; $i < count($id3v23); $i ++) { if (strpos($tag, $id3v23[$i] . chr(0)) != FALSE) { $pos = strpos($tag, $id3v23[$i] . chr(0)); $len = hexdec(bin2hex(substr($tag, ($pos + 5), 3))); $data = substr($tag, $pos, 9 + $len); for($a = 0; $a < strlen($data); $a ++) { $char = substr($data, $a, 1); if ($char >= " " && $char <= "~") $tmp .= $char; } if (substr($tmp, 0, 4) == "TIT2") $result['Title'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "TALB") $result['Album'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "TPE1") $result['Author'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "TRCK") $result['Track'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "TDRC") $result['Year'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "TLEN") $result['Lenght'] = substr($tmp, 4); if (substr($tmp, 0, 4) == "USLT") $result['Lyric'] = substr($tmp, 7); $tmp = ""; } } } if ($result['Version'] == "2.0") { for($i = 0; $i < count($id3v22); $i ++) { if (strpos($tag, $id3v22[$i] . chr(0)) != FALSE) { $pos = strpos($tag, $id3v22[$i] . chr(0)); $len = hexdec(bin2hex(substr($tag, ($pos + 3), 3))); $data = substr($tag, $pos, 6 + $len); for($a = 0; $a < strlen($data); $a ++) { $char = substr($data, $a, 1); if ($char >= " " && $char <= "~") $tmp .= $char; } if (substr($tmp, 0, 3) == "TT2") $result['Title'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "TAL") $result['Album'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "TP1") $result['Author'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "TRK") $result['Track'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "TYE") $result['Year'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "TLE") $result['Lenght'] = substr($tmp, 3); if (substr($tmp, 0, 3) == "ULT") $result['Lyric'] = substr($tmp, 6); $tmp = ""; } } } return $result; }
You can try foreach ( tagReader("4.mp3") as $name => $value ) { printf("<p>%s:%s</p>", $name, $value); }
This is because you are returning an array. If you want to print out the contents of the array's elements, you will have to loop through the array and print each element instead of returning the whole array. Something like: foreach ($results as $key => $value) echo $key . " " . $value;
How to format numbers in php 1,000 to 1k
Im trying to format the output of numbers in php. I have an amount of posts that show up, and next to each user is the total of posts. But it shows that actual amount, i want it to show it in a shorter format, actually, just like they do here at SO with reputation any ideas?
<? $numbers = array(100,1000,15141,3421); function format_number($number) { if($number >= 1000) { return $number/1000 . "k"; // NB: you will want to round this } else { return $number; } } foreach($numbers as $number) { echo $number . " : " . format_number($number); echo "\n"; }
function count_format($n, $point='.', $sep=',') { if ($n < 0) { return 0; } if ($n < 10000) { return number_format($n, 0, $point, $sep); } $d = $n < 1000000 ? 1000 : 1000000; $f = round($n / $d, 1); return number_format($f, $f - intval($f) ? 1 : 0, $point, $sep) . ($d == 1000 ? 'k' : 'M'); }
Use This Shorten long numbers to K/M/B? function number_format_short( $n, $precision = 1 ) { if ($n < 900) { // 0 - 900 $n_format = number_format($n, $precision); $suffix = ''; } else if ($n < 900000) { // 0.9k-850k $n_format = number_format($n / 1000, $precision); $suffix = 'K'; } else if ($n < 900000000) { // 0.9m-850m $n_format = number_format($n / 1000000, $precision); $suffix = 'M'; } else if ($n < 900000000000) { // 0.9b-850b $n_format = number_format($n / 1000000000, $precision); $suffix = 'B'; } else { // 0.9t+ $n_format = number_format($n / 1000000000000, $precision); $suffix = 'T'; }
Rounding to the Nearest Ending Digits
I have the following function that rounds a number to the nearest number ending with the digits of $nearest, and I was wondering if there is a more elegant way of doing the same. /** * Rounds the number to the nearest digit(s). * * #param int $number * #param int $nearest * #return int */ function roundNearest($number, $nearest, $type = null) { $result = abs(intval($number)); $nearest = abs(intval($nearest)); if ($result <= $nearest) { $result = $nearest; } else { $ceil = $nearest - substr($result, strlen($result) - strlen($nearest)); $floor = $nearest - substr($result, strlen($result) - strlen($nearest)) - pow(10, strlen($nearest)); switch ($type) { case 'ceil': $result += $ceil; break; case 'floor': $result += $floor; break; default: $result += (abs($ceil) <= abs($floor)) ? $ceil : $floor; break; } } if ($number < 0) { $result *= -1; } return $result; } Some examples: roundNearest(86, 9); // 89 roundNearest(97, 9); // 99 roundNearest(97, 9, 'floor'); // 89 Thanks in advance! PS: This question is not about rounding to the nearest multiple.
This works for me: function roundToDigits($num, $suffix, $type = 'round') { $pow = pow(10, floor(log($suffix, 10) + 1)); return $type(($num - $suffix) / $pow) * $pow + $suffix; }; $type should be either "ceil", "floor", or "round"
I think this should work, and it's more elegant to me, at least: function roundNearest($number, $nearest, $type = null) { if($number < 0) return -roundNearest(-$number, $nearest, $type); $nearest = abs($nearest); if($number < $nearest) return $nearest; $len = strlen($nearest); $pow = pow(10, $len); $diff = $pow - $nearest; if($type == 'ciel') $adj = 0.5; else if($type == 'floor') $adj = -0.5; else $adj = 0; return round(($number + $diff)/$pow + $adj)*$pow - $diff; } Edit: Added what I think you want from negative inputs.