|
@@ -43,50 +43,73 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
|
|
|
[STRING_UNITS_10] = 1000,
|
|
[STRING_UNITS_10] = 1000,
|
|
|
[STRING_UNITS_2] = 1024,
|
|
[STRING_UNITS_2] = 1024,
|
|
|
};
|
|
};
|
|
|
- int i, j;
|
|
|
|
|
- u32 remainder = 0, sf_cap, exp;
|
|
|
|
|
|
|
+ static const unsigned int rounding[] = { 500, 50, 5 };
|
|
|
|
|
+ int i = 0, j;
|
|
|
|
|
+ u32 remainder = 0, sf_cap;
|
|
|
char tmp[8];
|
|
char tmp[8];
|
|
|
const char *unit;
|
|
const char *unit;
|
|
|
|
|
|
|
|
tmp[0] = '\0';
|
|
tmp[0] = '\0';
|
|
|
- i = 0;
|
|
|
|
|
- if (!size)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (blk_size == 0)
|
|
|
|
|
+ size = 0;
|
|
|
|
|
+ if (size == 0)
|
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
|
|
- while (blk_size >= divisor[units]) {
|
|
|
|
|
- remainder = do_div(blk_size, divisor[units]);
|
|
|
|
|
|
|
+ /* This is Napier's algorithm. Reduce the original block size to
|
|
|
|
|
+ *
|
|
|
|
|
+ * coefficient * divisor[units]^i
|
|
|
|
|
+ *
|
|
|
|
|
+ * we do the reduction so both coefficients are just under 32 bits so
|
|
|
|
|
+ * that multiplying them together won't overflow 64 bits and we keep
|
|
|
|
|
+ * as much precision as possible in the numbers.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Note: it's safe to throw away the remainders here because all the
|
|
|
|
|
+ * precision is in the coefficients.
|
|
|
|
|
+ */
|
|
|
|
|
+ while (blk_size >> 32) {
|
|
|
|
|
+ do_div(blk_size, divisor[units]);
|
|
|
i++;
|
|
i++;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- exp = divisor[units] / (u32)blk_size;
|
|
|
|
|
- /*
|
|
|
|
|
- * size must be strictly greater than exp here to ensure that remainder
|
|
|
|
|
- * is greater than divisor[units] coming out of the if below.
|
|
|
|
|
- */
|
|
|
|
|
- if (size > exp) {
|
|
|
|
|
- remainder = do_div(size, divisor[units]);
|
|
|
|
|
- remainder *= blk_size;
|
|
|
|
|
|
|
+ while (size >> 32) {
|
|
|
|
|
+ do_div(size, divisor[units]);
|
|
|
i++;
|
|
i++;
|
|
|
- } else {
|
|
|
|
|
- remainder *= size;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /* now perform the actual multiplication keeping i as the sum of the
|
|
|
|
|
+ * two logarithms */
|
|
|
size *= blk_size;
|
|
size *= blk_size;
|
|
|
- size += remainder / divisor[units];
|
|
|
|
|
- remainder %= divisor[units];
|
|
|
|
|
|
|
|
|
|
|
|
+ /* and logarithmically reduce it until it's just under the divisor */
|
|
|
while (size >= divisor[units]) {
|
|
while (size >= divisor[units]) {
|
|
|
remainder = do_div(size, divisor[units]);
|
|
remainder = do_div(size, divisor[units]);
|
|
|
i++;
|
|
i++;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /* work out in j how many digits of precision we need from the
|
|
|
|
|
+ * remainder */
|
|
|
sf_cap = size;
|
|
sf_cap = size;
|
|
|
for (j = 0; sf_cap*10 < 1000; j++)
|
|
for (j = 0; sf_cap*10 < 1000; j++)
|
|
|
sf_cap *= 10;
|
|
sf_cap *= 10;
|
|
|
|
|
|
|
|
- if (j) {
|
|
|
|
|
|
|
+ if (units == STRING_UNITS_2) {
|
|
|
|
|
+ /* express the remainder as a decimal. It's currently the
|
|
|
|
|
+ * numerator of a fraction whose denominator is
|
|
|
|
|
+ * divisor[units], which is 1 << 10 for STRING_UNITS_2 */
|
|
|
remainder *= 1000;
|
|
remainder *= 1000;
|
|
|
- remainder /= divisor[units];
|
|
|
|
|
|
|
+ remainder >>= 10;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* add a 5 to the digit below what will be printed to ensure
|
|
|
|
|
+ * an arithmetical round up and carry it through to size */
|
|
|
|
|
+ remainder += rounding[j];
|
|
|
|
|
+ if (remainder >= 1000) {
|
|
|
|
|
+ remainder -= 1000;
|
|
|
|
|
+ size += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (j) {
|
|
|
snprintf(tmp, sizeof(tmp), ".%03u", remainder);
|
|
snprintf(tmp, sizeof(tmp), ".%03u", remainder);
|
|
|
tmp[j+1] = '\0';
|
|
tmp[j+1] = '\0';
|
|
|
}
|
|
}
|