humanize_number(3): fix math edge case in rounding large numbers

Fix for remainder overflow, when in rare cases adding remainder to divider
exceeded 1 and turned the total to 1000 in final formatting, taking up
the space for the unit character.

The fix continues the division of the original number if the above case
happens -- added the appropriate check to the for loop performing
the division. This lowers the value shown, to make it fit into the buffer
space provided (1.0M for 4+1 character buffer, as used by ls).

Add test case for the reported bug and extend test program to support
providing buffer length (ls -lh uses 5, tests hard-coded 4).

PR:		224498
Submitted by:	Pawel Biernacki <pawel.biernacki@gmail.com>
Reported by:	Masachika Ishizuka <ish@amail.plala.or.jp>
Reviewed by:	cem, kib
Approved by:	cem, kib
MFC after:	1 week
Sponsored by:	Mysterious Code Ltd.
Differential Revision:	D13578
This commit is contained in:
Bartek Rutkowski 2017-12-28 22:57:34 +00:00
parent 0080a8fa95
commit e285e32e56
3 changed files with 289 additions and 286 deletions

View File

@ -200,3 +200,9 @@ The
.Dv HN_IEC_PREFIXES .Dv HN_IEC_PREFIXES
flag was introduced in flag was introduced in
.Fx 9.0 . .Fx 9.0 .
.Sh CAVEATS
For numbers greater than 999 using buffer length of 4 and less can cause
rounding errors.
When using
.Dv HN_IEC_PREFIXES
the same error occurs for buffer length of 5 or less.

View File

@ -145,7 +145,8 @@ humanize_number(char *buf, size_t len, int64_t quotient,
*/ */
for (i = 0; for (i = 0;
(quotient >= max || (quotient == max - 1 && (quotient >= max || (quotient == max - 1 &&
remainder >= divisordeccut)) && i < maxscale; i++) { (remainder >= divisordeccut || remainder >=
divisor / 2))) && i < maxscale; i++) {
remainder = quotient % divisor; remainder = quotient % divisor;
quotient /= divisor; quotient /= divisor;
} }

View File

@ -49,333 +49,337 @@ static struct {
int64_t num; int64_t num;
int flags; int flags;
int scale; int scale;
size_t buflen;
} test_args[] = { } test_args[] = {
/* tests 0-13 test 1000 suffixes */ /* tests 0-13 test 1000 suffixes */
{ 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
/* tests 14-27 test 1024 suffixes */ /* tests 14-27 test 1024 suffixes */
{ 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE }, { 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE }, { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE }, { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE }, { 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE }, { 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE }, { 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE }, { 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE }, { 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 4 },
/* tests 28-37 test rounding */ /* tests 28-37 test rounding */
{ 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 4 },
{ 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE }, { 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE, 4 },
{ 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE }, { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE, 4 },
{ 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE }, { 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE }, { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE, 4 },
{ 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE }, { 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE, 4 },
{ 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE }, { 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE, 4 },
/* tests 38-61 test specific scale factors with 1000 divisor */ /* tests 38-61 test specific scale factors with 1000 divisor */
{ 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1 }, { 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1, 4 },
{ 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1 }, { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1, 4 },
{ 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2 }, { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2, 4 },
{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2 }, { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2, 4 },
{ 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3 }, { 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3, 4 },
{ 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3 }, { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3, 4 },
{ 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4 }, { 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4, 4 },
{ 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4 }, { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4, 4 },
{ 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5 }, { 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 },
{ 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 },
{ 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 },
{ 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 },
{ 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1 }, { 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1, 4 },
{ 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1 }, { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1, 4 },
{ 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2 }, { 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2, 4 },
{ 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2 }, { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2, 4 },
{ 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3 }, { 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3, 4 },
{ 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3 }, { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3, 4 },
{ 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4 }, { 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4, 4 },
{ 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4 }, { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4, 4 },
{ 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5 }, { 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 },
{ 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 4 },
{ 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 },
{ 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 4 },
/* tests 62-85 test specific scale factors with 1024 divisor */ /* tests 62-85 test specific scale factors with 1024 divisor */
{ 3, "0 K", (int64_t)0L, 0, 1 }, { 3, "0 K", (int64_t)0L, 0, 1, 4 },
{ 3, "1 K", (int64_t)512L, 0, 1 }, { 3, "1 K", (int64_t)512L, 0, 1, 4 },
{ 3, "0 M", (int64_t)512L, 0, 2 }, { 3, "0 M", (int64_t)512L, 0, 2, 4 },
{ 3, "1 M", (int64_t)512*1024L, 0, 2 }, { 3, "1 M", (int64_t)512*1024L, 0, 2, 4 },
{ 3, "0 G", (int64_t)512*1024L, 0, 3 }, { 3, "0 G", (int64_t)512*1024L, 0, 3, 4 },
{ 3, "1 G", (int64_t)512*1024*1024L, 0, 3 }, { 3, "1 G", (int64_t)512*1024*1024L, 0, 3, 4 },
{ 3, "0 T", (int64_t)512*1024*1024L, 0, 4 }, { 3, "0 T", (int64_t)512*1024*1024L, 0, 4, 4 },
{ 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4 }, { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4, 4 },
{ 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5 }, { 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5, 4 },
{ 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5 }, { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5, 4 },
{ 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6, 4 },
{ 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6, 4 },
{ 3, "0 K", (int64_t)1L, 0, 1 }, { 3, "0 K", (int64_t)1L, 0, 1, 4 },
{ 3, "2 K", (int64_t)1536L, 0, 1 }, { 3, "2 K", (int64_t)1536L, 0, 1, 4 },
{ 3, "0 M", (int64_t)1536L, 0, 2 }, { 3, "0 M", (int64_t)1536L, 0, 2, 4 },
{ 3, "2 M", (int64_t)1536*1024L, 0, 2 }, { 3, "2 M", (int64_t)1536*1024L, 0, 2, 4 },
{ 3, "0 G", (int64_t)1536*1024L, 0, 3 }, { 3, "0 G", (int64_t)1536*1024L, 0, 3, 4 },
{ 3, "2 G", (int64_t)1536*1024*1024L, 0, 3 }, { 3, "2 G", (int64_t)1536*1024*1024L, 0, 3, 4 },
{ 3, "0 T", (int64_t)1536*1024*1024L, 0, 4 }, { 3, "0 T", (int64_t)1536*1024*1024L, 0, 4, 4 },
{ 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4 }, { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4, 4 },
{ 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5 }, { 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5, 4 },
{ 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5 }, { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5, 4 },
{ 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6, 4 },
{ 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6, 4 },
/* tests 86-99 test invalid specific scale values of < 0 or >= 7 with /* tests 86-99 test invalid specific scale values of < 0 or >= 7 with
and without HN_DIVISOR_1000 set */ and without HN_DIVISOR_1000 set */
/* all should return errors with new code; with old, the latter 3 /* all should return errors with new code; with old, the latter 3
are instead processed as if having AUTOSCALE and/or GETSCALE set */ are instead processed as if having AUTOSCALE and/or GETSCALE set */
{ -1, "", (int64_t)1L, 0, 7 }, { -1, "", (int64_t)1L, 0, 7, 4 },
{ -1, "", (int64_t)1L, HN_DIVISOR_1000, 7 }, { -1, "", (int64_t)1L, HN_DIVISOR_1000, 7, 4 },
{ -1, "", (int64_t)1L, 0, 1000 }, { -1, "", (int64_t)1L, 0, 1000, 4 },
{ -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000 }, { -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000, 4 },
{ -1, "", (int64_t)0L, 0, 1000*1000 }, { -1, "", (int64_t)0L, 0, 1000*1000, 4 },
{ -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000 }, { -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000, 4 },
{ -1, "", (int64_t)0L, 0, INT_MAX }, { -1, "", (int64_t)0L, 0, INT_MAX, 4 },
{ -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX }, { -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX, 4 },
/* Negative scale values are not handled well /* Negative scale values are not handled well
by the existing library routine - should report as error */ by the existing library routine - should report as error */
/* all should return errors with new code, fail assertion with old */ /* all should return errors with new code, fail assertion with old */
{ -1, "", (int64_t)1L, 0, -1 }, { -1, "", (int64_t)1L, 0, -1, 4 },
{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -1 }, { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1, 4 },
{ -1, "", (int64_t)1L, 0, -1000 }, { -1, "", (int64_t)1L, 0, -1000, 4 },
{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000 }, { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000, 4 },
/* __INT_MIN doesn't print properly, skipped. */ /* __INT_MIN doesn't print properly, skipped. */
{ -1, "", (int64_t)1L, 0, -__INT_MAX }, { -1, "", (int64_t)1L, 0, -__INT_MAX, 4 },
{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX }, { -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX, 4 },
/* tests for scale == 0, without autoscale */ /* tests for scale == 0, without autoscale */
/* tests 100-114 test scale 0 with 1000 divisor - print first N digits */ /* tests 100-114 test scale 0 with 1000 divisor - print first N digits */
{ 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0 }, { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0, 4 },
{ 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0 }, { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0, 4 },
{ 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0 }, { 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0, 4 },
{ 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE }, { 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE, 4 },
{ 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE }, { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE, 4 },
{ 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE }, { 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE, 4 },
{ 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0 }, { 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0, 4 },
{ 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0 }, { 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0, 4 },
{ 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0 }, { 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0, 4 },
{ 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0 }, { 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0, 4 },
{ 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0 }, { 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0, 4 },
{ 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0 }, { 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0, 4 },
{ 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0 }, { 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0, 4 },
{ 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0 }, { 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0, 4 },
{ 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0 }, { 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0, 4 },
/* tests 115-126 test scale 0 with 1024 divisor - print first N digits */ /* tests 115-126 test scale 0 with 1024 divisor - print first N digits */
{ 2, "0 ", (int64_t)0L, 0, 0 }, { 2, "0 ", (int64_t)0L, 0, 0, 4 },
{ 2, "1 ", (int64_t)1L, 0, 0 }, { 2, "1 ", (int64_t)1L, 0, 0, 4 },
{ 3, "10 ", (int64_t)10L, 0, 0 }, { 3, "10 ", (int64_t)10L, 0, 0, 4 },
{ 4, "150", (int64_t)150L, 0, 0 }, { 4, "150", (int64_t)150L, 0, 0, 4 },
{ 4, "500", (int64_t)500L, 0, 0 }, { 4, "500", (int64_t)500L, 0, 0, 4 },
{ 4, "999", (int64_t)999L, 0, 0 }, { 4, "999", (int64_t)999L, 0, 0, 4 },
{ 5, "100", (int64_t)1000L, 0, 0 }, { 5, "100", (int64_t)1000L, 0, 0, 4 },
{ 5, "150", (int64_t)1500L, 0, 0 }, { 5, "150", (int64_t)1500L, 0, 0, 4 },
{ 7, "500", (int64_t)500*1000L, 0, 0 }, { 7, "500", (int64_t)500*1000L, 0, 0, 4 },
{ 8, "150", (int64_t)1500*1000L, 0, 0 }, { 8, "150", (int64_t)1500*1000L, 0, 0, 4 },
{ 10, "500", (int64_t)500*1000*1000L, 0, 0 }, { 10, "500", (int64_t)500*1000*1000L, 0, 0, 4 },
{ 11, "150", (int64_t)1500*1000*1000L, 0, 0 }, { 11, "150", (int64_t)1500*1000*1000L, 0, 0, 4 },
/* Test case for rounding of edge numbers around 999.5+, see PR224498.
* Require buflen >= 5 */
{ 4, "1.0M", (int64_t)1023500, HN_DECIMAL|HN_B|HN_NOSPACE, HN_AUTOSCALE, 5 },
/* Test boundary cases for very large positive/negative number formatting */ /* Test boundary cases for very large positive/negative number formatting */
/* Explicit scale, divisor 1024 */ /* Explicit scale, divisor 1024 */
/* XXX = requires length 5 (buflen 6) for some cases*/ /* Requires buflen >= 6 */
/* KLUDGE - test loop below will bump length 5 up to 5 */ { 3, "8 E", INT64_MAX, 0, 6, 6 },
{ 3, "8 E", INT64_MAX, 0, 6 }, { 4, "-8 E", -INT64_MAX, 0, 6, 6 },
{ 4, "-8 E", -INT64_MAX, 0, 6 }, { 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6 }, { 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6, 6 },
{ 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6 }, { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5 }, { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5 }, { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5 }, { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5 }, { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5 }, { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5, 6 },
{ 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5 },
/* Explicit scale, divisor 1000 */ /* Explicit scale, divisor 1000 */
{ 3, "9 E", INT64_MAX, HN_DIVISOR_1000, 6 }, { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, 6, 6 },
{ 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, 6 }, { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, 6, 6 },
{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 },
{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 },
{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 },
{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 }, { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6, 6 },
{ 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 },
{ 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 },
{ 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 },
{ 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 }, { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5, 6 },
/* Autoscale, divisor 1024 */ /* Autoscale, divisor 1024 */
{ 3, "8 E", INT64_MAX, 0, HN_AUTOSCALE }, { 3, "8 E", INT64_MAX, 0, HN_AUTOSCALE, 6 },
{ 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE }, { 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE, 6 },
{ 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
{ 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
{ 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
{ 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
{ 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
{ 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE }, { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE, 6 },
/* Autoscale, divisor 1000 */ /* Autoscale, divisor 1000 */
{ 3, "9 E", INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE }, { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE }, { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
/* 0 scale, divisor 1024 */ /* 0 scale, divisor 1024 */
{ 12, "skdj", INT64_MAX, 0, 0 }, { 12, "skdj", INT64_MAX, 0, 0, 6 },
{ 21, "-9223", -INT64_MAX, 0, 0 }, { 21, "-9223", -INT64_MAX, 0, 0, 6 },
{ 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0 }, { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0, 6 },
{ 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0 }, { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0, 6 },
{ 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0 }, { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0, 6 },
{ 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0 }, { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0, 6 },
{ 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0 }, { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0, 6 },
{ 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0 }, { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0, 6 },
/* 0 scale, divisor 1000 */ /* 0 scale, divisor 1000 */
/* XXX - why does this fail? */ /* XXX - why does this fail? */
{ -1, "", INT64_MAX, HN_DIVISOR_1000, 0 }, { -1, "", INT64_MAX, HN_DIVISOR_1000, 0, 6 },
{ 21, "-9223", -INT64_MAX, HN_DIVISOR_1000, 0 }, { 21, "-9223", -INT64_MAX, HN_DIVISOR_1000, 0, 6 },
{ 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
{ 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
{ 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
{ 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
/* Expected to pass */ /* Expected to pass */
{ 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
{ 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 }, { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0, 6 },
/* Need to implement tests for GETSCALE */ /* Need to implement tests for GETSCALE */
/* { ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE }, /* { ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE, 6 },
... ...
*/ */
/* Tests for HN_DECIMAL */ /* Tests for HN_DECIMAL */
/* Positive, Autoscale */ /* Positive, Autoscale */
{ 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
/* XXX - shouldn't the following two be "10. M"? */ /* XXX - shouldn't the following two be "10. M"? */
{ 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
/* Negative, Autoscale - should pass */ /* Negative, Autoscale - should pass */
{ 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE }, { 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE, 6 },
/* Positive/negative, at maximum scale */ /* Positive/negative, at maximum scale */
{ 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
/* Negatives work with latest rev only: */ /* Negatives work with latest rev only: */
{ 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE }, { 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE, 6 },
{ 5, "8.0 E", INT64_MAX, HN_DECIMAL, HN_AUTOSCALE }, { 5, "8.0 E", INT64_MAX, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 5, "7.9 E", INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE }, { 5, "7.9 E", INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE }, { 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE, 6 },
{ 6, "-7.9 ", -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE }, { 6, "-7.9 ", -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE, 6 },
/* Positive, Fixed scales */ /* Positive, Fixed scales */
{ 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 },
{ 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, { 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 },
{ 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, { 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 },
{ 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 }, { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1, 6 },
{ 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 }, { 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3, 6 },
{ 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 }, { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2, 6 },
{ 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 }, { 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3, 6 },
/* Positive/negative, at maximum scale */ /* Positive/negative, at maximum scale */
{ 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 }, { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5, 6 },
{ 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 },
{ 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 },
{ 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 }, { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6, 6 },
{ 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6 }, { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6, 6 },
/* HN_DECIMAL + binary + fixed scale cases not completed */ /* HN_DECIMAL + binary + fixed scale cases not completed */
{ 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1 }, { 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1, 6 },
{ 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2 }, { 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2, 6 },
/* Negative, Fixed scales */ /* Negative, Fixed scales */
/* Not yet added, but should work with latest rev */ /* Not yet added, but should work with latest rev */
@ -439,9 +443,9 @@ static struct {
} flags[] = { } flags[] = {
{ HN_AUTOSCALE, "HN_AUTOSCALE" }, { HN_AUTOSCALE, "HN_AUTOSCALE" },
{ HN_GETSCALE, "HN_GETSCALE" }, { HN_GETSCALE, "HN_GETSCALE" },
{ HN_DIVISOR_1000, "HN_DIVISOR_1000"}, { HN_DIVISOR_1000, "HN_DIVISOR_1000" },
{ HN_B, "HN_B"}, { HN_B, "HN_B" },
{ HN_DECIMAL, "HN_DECIMAL"}, { HN_DECIMAL, "HN_DECIMAL" },
}; };
static const char *separator = "|"; static const char *separator = "|";
@ -496,13 +500,14 @@ main(int argc, char * const argv[])
{ {
char *buf; char *buf;
char *flag_str, *scale_str; char *flag_str, *scale_str;
size_t buflen, errcnt, i, skipped, tested; size_t blen, buflen, errcnt, i, skipped, tested;
int r; int r;
int includeNegScale; int includeNegScale;
int includeExabyteTests; int includeExabyteTests;
int verbose; int verbose;
buflen = 4; buf = NULL;
buflen = 0;
includeNegScale = 0; includeNegScale = 0;
includeExabyteTests = 0; includeExabyteTests = 0;
verbose = 0; verbose = 0;
@ -510,7 +515,6 @@ main(int argc, char * const argv[])
read_options(argc, argv, &buflen, &includeNegScale, read_options(argc, argv, &buflen, &includeNegScale,
&includeExabyteTests, &verbose); &includeExabyteTests, &verbose);
buf = malloc(buflen);
errcnt = 0; errcnt = 0;
tested = 0; tested = 0;
skipped = 0; skipped = 0;
@ -520,16 +524,8 @@ main(int argc, char * const argv[])
printf("1..%zu\n", nitems(test_args)); printf("1..%zu\n", nitems(test_args));
for (i = 0; i < nitems(test_args); i++) { for (i = 0; i < nitems(test_args); i++) {
/* KLUDGE */ blen = (buflen > 0) ? buflen : test_args[i].buflen;
if (test_args[i].num == INT64_MAX && buflen == 4) { buf = realloc(buf, blen);
/* Start final tests which require buffer of 6 */
free(buf);
buflen = 6;
buf = malloc(buflen);
if (verbose)
printf("Buffer length increased to %zu\n",
buflen);
}
if (test_args[i].scale < 0 && ! includeNegScale) { if (test_args[i].scale < 0 && ! includeNegScale) {
skipped++; skipped++;
@ -542,7 +538,7 @@ main(int argc, char * const argv[])
continue; continue;
} }
r = humanize_number(buf, buflen, test_args[i].num, "", r = humanize_number(buf, blen, test_args[i].num, "",
test_args[i].scale, test_args[i].flags); test_args[i].scale, test_args[i].flags);
flag_str = str_flags(test_args[i].flags, "[no flags]"); flag_str = str_flags(test_args[i].flags, "[no flags]");
scale_str = str_scale(test_args[i].scale); scale_str = str_scale(test_args[i].scale);
@ -553,7 +549,7 @@ main(int argc, char * const argv[])
"buflen: %zu, got: %d + \"%s\", " "buflen: %zu, got: %d + \"%s\", "
"expected %d + \"%s\"; num = %jd, " "expected %d + \"%s\"; num = %jd, "
"scale = %s, flags= %s.\n", "scale = %s, flags= %s.\n",
i, buflen, r, buf, test_args[i].retval, i, blen, r, buf, test_args[i].retval,
test_args[i].res, test_args[i].res,
(intmax_t)test_args[i].num, (intmax_t)test_args[i].num,
scale_str, flag_str); scale_str, flag_str);
@ -565,10 +561,10 @@ main(int argc, char * const argv[])
if (verbose) if (verbose)
printf("result mismatch on index %zu, got: " printf("result mismatch on index %zu, got: "
"\"%s\", expected \"%s\"; num = %jd, " "\"%s\", expected \"%s\"; num = %jd, "
"scale = %s, flags= %s.\n", "buflen: %zu, scale = %s, flags= %s.\n",
i, buf, test_args[i].res, i, buf, test_args[i].res,
(intmax_t)test_args[i].num, (intmax_t)test_args[i].num,
scale_str, flag_str); blen, scale_str, flag_str);
else else
printf("not ok %zu # buf \"%s\" != \"%s\"\n", printf("not ok %zu # buf \"%s\" != \"%s\"\n",
i + 1, buf, test_args[i].res); i + 1, buf, test_args[i].res);
@ -577,15 +573,15 @@ main(int argc, char * const argv[])
if (verbose) if (verbose)
printf("successful result on index %zu, " printf("successful result on index %zu, "
"returned %d, got: \"%s\"; num = %jd, " "returned %d, got: \"%s\"; num = %jd, "
"scale = %s, flags= %s.\n", "buflen = %zd, scale = %s, flags= %s.\n",
i, r, buf, i, r, buf, (intmax_t)test_args[i].num,
(intmax_t)test_args[i].num, blen, scale_str, flag_str);
scale_str, flag_str);
else else
printf("ok %zu\n", i + 1); printf("ok %zu\n", i + 1);
} }
tested++; tested++;
} }
free(buf);
if (verbose) if (verbose)
printf("total errors: %zu/%zu tests, %zu skipped\n", errcnt, printf("total errors: %zu/%zu tests, %zu skipped\n", errcnt,