From e1c9c92abdd5cb05f868ee5d7ce87ec46cef5ef7 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 15 Jun 2000 01:40:09 +0000 Subject: [PATCH] (human_readable_inexact): Allow an input block size that is not a multiple of the output block size, and vice versa. --- lib/human.c | 85 +++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/lib/human.c b/lib/human.c index 5cfbce9..839ecda 100644 --- a/lib/human.c +++ b/lib/human.c @@ -90,9 +90,8 @@ human_readable (uintmax_t n, char *buf, N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must be nonnegative. - If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in - the output number. OUTPUT_BLOCK_SIZE must be a multiple of - FROM_BLOCK_SIZE or vice versa. + OUTPUT_BLOCK_SIZE must be nonzero. If it is positive, use units of + OUTPUT_BLOCK_SIZE in the output number. Use INEXACT_STYLE to determine whether to take the ceiling or floor of any result that cannot be expressed exactly. @@ -118,6 +117,10 @@ human_readable_inexact (uintmax_t n, char *buf, int base; int to_block_size; int tenths = 0; + int multiplier; + int divisor; + int r2; + int r10; int power; char *p; @@ -148,57 +151,49 @@ human_readable_inexact (uintmax_t n, char *buf, /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */ - if (to_block_size <= from_block_size) + if (to_block_size <= from_block_size + ? (from_block_size % to_block_size != 0 + || (multiplier = from_block_size / to_block_size, + (amt = n * multiplier) / multiplier != n)) + : (from_block_size == 0 + || to_block_size % from_block_size != 0 + || (divisor = to_block_size / from_block_size, + r10 = (n % divisor) * 10, + r2 = (r10 % divisor) * 2, + amt = n / divisor, + tenths = r10 / divisor, + rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2), + 0))) { - int multiplier = from_block_size / to_block_size; - amt = n * multiplier; + /* Either the result cannot be computed easily using uintmax_t, + or from_block_size is zero. Fall back on floating point. + FIXME: This can yield answers that are slightly off. */ - if (amt / multiplier != n) - { - /* Overflow occurred during multiplication. We should use - multiple precision arithmetic here, but we'll be lazy and - resort to floating point. This can yield answers that - are slightly off. In practice it is quite rare to - overflow uintmax_t, so this is good enough for now. */ + double damt = n * (from_block_size / (double) to_block_size); - double damt = n * (double) multiplier; + if (! base) + sprintf (buf, "%.0f", damt); + else + { + double e = 1; + power = 0; - if (! base) - sprintf (buf, "%.0f", damt); - else + do { - double e = 1; - power = 0; - - do - { - e *= base; - power++; - } - while (e * base <= damt && power < sizeof suffixes - 1); - - damt /= e; - - sprintf (buf, "%.1f%c", damt, suffixes[power]); - if (4 < strlen (buf)) - sprintf (buf, "%.0f%c", damt, suffixes[power]); + e *= base; + power++; } + while (e * base <= damt && power < sizeof suffixes - 1); - return buf; + damt /= e; + + sprintf (buf, "%.1f%c", damt, suffixes[power]); + if (4 < strlen (buf)) + sprintf (buf, "%.0f%c", damt, suffixes[power]); } - } - else if (from_block_size == 0) - amt = 0; - else - { - int divisor = to_block_size / from_block_size; - int r10 = (n % divisor) * 10; - int r2 = (r10 % divisor) * 2; - amt = n / divisor; - tenths = r10 / divisor; - rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2); - } + return buf; + } /* Use power of BASE notation if adjusted AMT is large enough. */ -- 2.45.2