Add support for IEE/IEC (and now also SI) power of two notions of

prefixes (Ki, Mi, Gi...) for humanize_number(3).

Note that applications has to pass HN_IEC_PREFIXES to use this
feature for backward compatibility reasons.

Reviewed by:	arundel
MFC after:	2 weeks
This commit is contained in:
Xin LI 2011-04-12 22:48:03 +00:00
parent e94d5ad227
commit 7d14df1a2d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=220582
3 changed files with 89 additions and 27 deletions

View File

@ -28,7 +28,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 25, 2004
.Dd Apr 12, 2011
.Dt HUMANIZE_NUMBER 3
.Os
.Sh NAME
@ -68,17 +68,24 @@ then divide
by 1024 until it will.
In this case, prefix
.Fa suffix
with the appropriate SI designator.
with the appropriate designator.
The
.Fn humanize_number
function
follows the traditional computer science conventions rather than the proposed
SI power of two convention.
function follows the traditional computer science conventions by
default, rather than the IEE/IEC (and now also SI) power of two
convention or the power of ten notion.
This behaviour however can be altered by specifying the
.Dv HN_DIVISOR_1000
and
.Dv HN_IEC_PREFIXES
flags.
.Pp
The prefixes are:
The traditional
.Pq default
prefixes are:
.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent
.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" Ta Sy "Multiplier 1000x"
.It Li k Ta No kilo Ta 1024 Ta 1000
.It Li (note) Ta No kilo Ta 1024 Ta 1000
.It Li M Ta No mega Ta 1048576 Ta 1000000
.It Li G Ta No giga Ta 1073741824 Ta 1000000000
.It Li T Ta No tera Ta 1099511627776 Ta 1000000000000
@ -86,6 +93,20 @@ The prefixes are:
.It Li E Ta No exa Ta 1152921504606846976 Ta 1000000000000000000
.El
.Pp
Note:
An uppercase K indicates a power of two, a lowercase k a power of ten.
.Pp
The IEE/IEC (and now also SI) power of two prefixes are:
.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent
.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier"
.It Li Ki Ta No kibi Ta 1024
.It Li Mi Ta No mebi Ta 1048576
.It Li Gi Ta No gibi Ta 1073741824
.It Li Ti Ta No tebi Ta 1099511627776
.It Li Pi Ta No pebi Ta 1125899906842624
.It Li Ei Ta No exbi Ta 1152921504606846976
.El
.Pp
The
.Fa len
argument must be at least 4 plus the length of
@ -94,7 +115,12 @@ in order to ensure a useful result is generated into
.Fa buf .
To use a specific prefix, specify this as
.Fa scale
(multiplier = 1024 ^ scale).
.Po multiplier = 1024 ^ scale;
when
.Dv HN_DIVISOR_1000
is specified,
multiplier = 1000 ^ scale
.Pc .
This cannot be combined with any of the
.Fa scale
flags below.
@ -127,6 +153,11 @@ Use
Divide
.Fa number
with 1000 instead of 1024.
.It Dv HN_IEC_PREFIXES
Use the IEE/IEC notion of prefixes (Ki, Mi, Gi...).
This flag has no effect when
.Dv HN_DIVISOR_1000
is also specified.
.El
.Sh RETURN VALUES
The
@ -141,6 +172,18 @@ If
is specified, the prefix index number will be returned instead.
.Sh SEE ALSO
.Xr expand_number 3
.Sh STANDARDS
The
.Dv HN_DIVISOR_1000
and
.Dv HN_IEC_PREFIXES
flags
conform to
.Tn ISO/IEC
Std\~80000-13:2008
and
.Tn IEEE
Std\~1541-2002.
.Sh HISTORY
The
.Fn humanize_number
@ -148,3 +191,7 @@ function first appeared in
.Nx 2.0
and then in
.Fx 5.3 .
The
.Dv HN_IEC_PREFIXES
flag was introduced in
.Fx 9.0 .

View File

@ -42,45 +42,58 @@ __FBSDID("$FreeBSD$");
#include <locale.h>
#include <libutil.h>
static const int maxscale = 7;
int
humanize_number(char *buf, size_t len, int64_t quotient,
const char *suffix, int scale, int flags)
{
const char *prefixes, *sep;
int i, r, remainder, maxscale, s1, s2, sign;
int i, r, remainder, s1, s2, sign;
int64_t divisor, max;
size_t baselen;
assert(buf != NULL);
assert(suffix != NULL);
assert(scale >= 0);
assert(scale < maxscale || (((scale & (HN_AUTOSCALE | HN_GETSCALE)) != 0)));
assert(!((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES)));
remainder = 0;
if (flags & HN_DIVISOR_1000) {
/* SI for decimal multiplies */
divisor = 1000;
if (flags & HN_B)
prefixes = "B\0k\0M\0G\0T\0P\0E";
else
prefixes = "\0\0k\0M\0G\0T\0P\0E";
} else {
if (flags & HN_IEC_PREFIXES) {
baselen = 2;
/*
* binary multiplies
* XXX IEC 60027-2 recommends Ki, Mi, Gi...
* Use the prefixes for power of two recommended by
* the International Electrotechnical Commission
* (IEC) in IEC 80000-3 (i.e. Ki, Mi, Gi...).
*
* HN_IEC_PREFIXES implies a divisor of 1024 here
* (use of HN_DIVISOR_1000 would have triggered
* an assertion earlier).
*/
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0K\0M\0G\0T\0P\0E";
prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
else
prefixes = "\0\0K\0M\0G\0T\0P\0E";
prefixes = "\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
} else {
baselen = 1;
if (flags & HN_DIVISOR_1000)
divisor = 1000;
else
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
else
prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
}
#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
maxscale = 7;
#define SCALE2PREFIX(scale) (&prefixes[(scale) * 3])
if (scale >= maxscale &&
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
if (scale < 0 || (scale >= maxscale &&
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
return (-1);
if (buf == NULL || suffix == NULL)
@ -91,10 +104,10 @@ humanize_number(char *buf, size_t len, int64_t quotient,
if (quotient < 0) {
sign = -1;
quotient = -quotient;
baselen = 3; /* sign, digit, prefix */
baselen += 2; /* sign, digit */
} else {
sign = 1;
baselen = 2; /* digit, prefix */
baselen += 1; /* digit */
}
if (flags & HN_NOSPACE)
sep = "";

View File

@ -220,7 +220,9 @@ __END_DECLS
#define HN_NOSPACE 0x02
#define HN_B 0x04
#define HN_DIVISOR_1000 0x08
#define HN_IEC_PREFIXES 0x10
/* maxscale = 0x07 */
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20