bc: shrink zbc_num_ulong()
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Dec 2018 20:37:46 +0000 (21:37 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Dec 2018 20:37:46 +0000 (21:37 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/bc.c

index 7be2d0b9bb38b0975195167222848930ad368321..876244b34c38d08f1b624149d105642768cf0734 100644 (file)
@@ -1442,20 +1442,21 @@ static void bc_num_copy(BcNum *d, BcNum *s)
 static BC_STATUS zbc_num_ulong(BcNum *n, unsigned long *result_p)
 {
        size_t i;
-       unsigned long pow, result;
+       unsigned long result;
 
        if (n->neg) RETURN_STATUS(bc_error("negative number"));
 
-       for (result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
-               unsigned long prev = result, powprev = pow;
-
-               result += ((unsigned long) n->num[i]) * pow;
-               pow *= 10;
-
-               if (result < prev || pow < powprev)
+       result = 0;
+       i = n->len;
+       while (i > n->rdx) {
+               unsigned long prev = result;
+               result = result * 10 + n->num[--i];
+               // Even overflowed N*10 can still satisfy N*10>=N. For example,
+               //    0x1ff00000 * 10 is 0x13f600000,
+               // or 0x3f600000 truncated to 32 bits. Which is larger.
+               // However, (N*10)/8 < N check is always correct.
+               if ((result / 8) < prev)
                        RETURN_STATUS(bc_error("overflow"));
-               prev = result;
-               powprev = pow;
        }
        *result_p = result;