When I am on Unix system running things of from command line (either SQL or shell of any sort) with long number, I find these numbers hard to read. For example a printout of netstat packets shows |
236477161 packets |
Which is really 236.4 million packets, a human friendly representation will be more like
|
236,477,161 packets |
Same with SQL I run a count on number of rows in a table, I get something that is sort of unreadable:
|
mysql> select count(*) from feedz.quova;
+----------+
| count(*) |
+----------+
| 14339159 |
+----------+
|
Solution is to write your wrapper that does 1000's seperator with a comma. In MySQL now my numbers look a little more friendly
|
mysql> select functions.humanf(count(*)) from feedz.quova;
+------------------+
| humanf(count(*)) |
+------------------+
| 14,433,915 |
+------------------+
|
14.4 million, now that is reasonable. To enable this I made a flexible C-program that prints large numbers in human friendly way and a MySQL function that will support this human friendly print out of large numbers.
More in the demo below:
|
#Print me a number in comma separated (or locale defined separator like space) large number
sh-4.1$ ./humanf 485311298
485,311,298
#Print me number of Bytes in human friendly KibiBytes/MebiBytes disk+human friendly format basse^2
sh-4.1$ ./humanf -b Auto 485311298
462.82 MBytes
#Print me number of Bytes in human friendly KibiBytes format specifically
sh-4.1$ ./humanf -b KBytes 485311298
473,936.81 KBytes
#Print me number of Bytes in human friendly GibiBytes format specifically
sh-4.1$ ./humanf -b GBytes 485311298
0.45 GBytes
|
Code: / C-program compile with -lm flag for math support/
|
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
#include <inttypes.h>
#include <locale.h>
#include <math.h>
char *huprint(uint64_t n, const char *unit);
void _exitt(char *err);
const char *units[] = {"Auto","KBytes","MBytes","GBytes","TBytes","PBytes","EBytes","ZBytes"};
//Default Units
#define defunits ((const char*)"Bytes")
int main (int argc, char *argv[]) {
char *unit = NULL;
int opt;
uint64_t val;
if((opt=getopt(argc,argv,"b:")) != -1) {
if(opt == 'b')
unit=optarg;
else
_exitt("Incorrect usage .\n");
}
if(argc <= optind)
_exitt("Incorrect usage\n");
val = strtoull((const char *)argv[optind++], NULL, 10);
// printf("You entered a number like %s %"PRIu64"\n",unit,val);
if (errno == EINVAL)
{
_exitt("Error unable to parse the number");
}
else if (errno == ERANGE)
{
// does not fit in an unsigned long long
_exitt("Error unable to parse the number too big");
}
printf("%s\n", huprint(val,unit));
return 0;
}
void _exitt(char *err) {
printf("%s",err);
printf("Usage humanf [-b Auto|KBytes|MBytes] number\n");
exit(255);
}
char *huprint(uint64_t n,const char *unit)
{
static int comma = '\0';
static char retbuf[30];
char dec[5];
char *p = &retbuf[sizeof(retbuf)-1];
int i = 0;
int ak=0;
int aj=0;
double pr;
int NUNITS;
uint64_t j;
if(unit) {
// Find what unit people want if it is specified as Bytes / etc.
NUNITS=sizeof(units)/sizeof(*units);
for(i=0;i<NUNITS;i++)
if(strncmp(units[i],unit,sizeof(units[i])) ==0)
aj=i;
j=n;
// printf("%s %d %d \n",unit, aj , ak);
if(aj == 0) {
//User wants to Auto
aj=NUNITS-1;
while (n > 1024) {
n=n/1024;
ak++;
// if(ak >= aj) break;
}
}
else {
// Use the units provided by the user
while (ak < aj) {
n=n/1024;
ak++;
}
}
*p='\0';
if(ak > 0) {
i=(int)strlen(units[ak]);
while (i >= 0) {
*--p=units[ak][i];
i--;
}
} else {
i=(int)strlen(defunits);
while (i >= 0) {
*--p=defunits[i];
i--;
}
}
*--p=' ';
pr=j/pow(1024,ak)-n;
if(pr > 0) {
snprintf(dec,sizeof(dec),"%.3f",pr);
*--p=dec[3];
*--p=dec[2];
*--p=dec[1];
// printf("Decimal value %s",dec);
}
i=0;
}
else
*p = '\0';
if(comma == '\0') {
struct lconv *lcp = localeconv();
if(lcp != NULL) {
if(lcp->thousands_sep != NULL &&
*lcp->thousands_sep != '\0')
comma = *lcp->thousands_sep;
else comma = ',';
}
}
do {
if(i%3 == 0 && i != 0)
*--p = comma;
*--p = '0' + n % 10;
n /= 10;
i++;
} while(n != 0);
return p;
}
|
Code: MySQL function
|
delimiter $$
CREATE FUNCTION HUMANF(number INT) RETURNS TEXT BEGIN
DECLARE x TEXT;
DECLARE l int;
DECLARE k int;
DECLARE i int;
DECLARE f text;
SET x = CONCAT('',number);
SET l=length(x);
SET k=l%3;
if k > 0 then
SET f=CONCAT(SUBSTRING(x,1,k),",");
SET i=2;
else
SET f="";
SET i=k+1;
END IF;
mk_loop: LOOP
if i >= l then
LEAVE mk_loop;
END IF;
SET f=CONCAT(f,substring(x,i,3),",");
SET i=i+3;
END LOOP;
RETURN substring(f,1,length(f)-1);
END
$$
|
Enjoy - come to the human friendly world even in command line... |
No comments:
Post a Comment