All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: peter.maydell@linaro.org
Cc: "Alex Bennée" <alex.bennee@linaro.org>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	qemu-devel@nongnu.org
Subject: [PULL v2 01/15] utils: Use fixed-point arithmetic in qemu_strtosz
Date: Wed, 17 Mar 2021 07:22:02 +0000	[thread overview]
Message-ID: <20210317072216.16316-2-alex.bennee@linaro.org> (raw)
In-Reply-To: <20210317072216.16316-1-alex.bennee@linaro.org>

From: Richard Henderson <richard.henderson@linaro.org>

Once we've parsed the fractional value, extract it into an integral
64-bit fraction.  Perform the scaling with integer arithmetic, and
simplify the overflow detection.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210315185117.1986240-2-richard.henderson@linaro.org>

diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c
index bad3a60993..e025b54c05 100644
--- a/tests/unit/test-cutils.c
+++ b/tests/unit/test-cutils.c
@@ -2128,7 +2128,7 @@ static void test_qemu_strtosz_float(void)
     str = "12.345M";
     err = qemu_strtosz(str, &endptr, &res);
     g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB));
+    g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB + 0.5));
     g_assert(endptr == str + 7);
 }
 
diff --git a/util/cutils.c b/util/cutils.c
index d89a40a8c3..c442882b88 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -275,10 +275,9 @@ static int do_strtosz(const char *nptr, const char **end,
     int retval;
     const char *endptr, *f;
     unsigned char c;
-    bool mul_required = false, hex = false;
-    uint64_t val;
+    bool hex = false;
+    uint64_t val, valf = 0;
     int64_t mul;
-    double fraction = 0.0;
 
     /* Parse integral portion as decimal. */
     retval = qemu_strtou64(nptr, &endptr, 10, &val);
@@ -308,17 +307,19 @@ static int do_strtosz(const char *nptr, const char **end,
          * without fractional digits.  If we see an exponent, treat
          * the entire input as invalid instead.
          */
+        double fraction;
+
         f = endptr;
         retval = qemu_strtod_finite(f, &endptr, &fraction);
         if (retval) {
-            fraction = 0.0;
             endptr++;
         } else if (memchr(f, 'e', endptr - f) || memchr(f, 'E', endptr - f)) {
             endptr = nptr;
             retval = -EINVAL;
             goto out;
-        } else if (fraction != 0) {
-            mul_required = true;
+        } else {
+            /* Extract into a 64-bit fixed-point fraction. */
+            valf = (uint64_t)(fraction * 0x1p64);
         }
     }
     c = *endptr;
@@ -333,16 +334,35 @@ static int do_strtosz(const char *nptr, const char **end,
         mul = suffix_mul(default_suffix, unit);
         assert(mul > 0);
     }
-    if (mul == 1 && mul_required) {
-        endptr = nptr;
-        retval = -EINVAL;
-        goto out;
-    }
-    if (val > (UINT64_MAX - ((uint64_t) (fraction * mul))) / mul) {
-        retval = -ERANGE;
-        goto out;
+    if (mul == 1) {
+        /* When a fraction is present, a scale is required. */
+        if (valf != 0) {
+            endptr = nptr;
+            retval = -EINVAL;
+            goto out;
+        }
+    } else {
+        uint64_t valh, tmp;
+
+        /* Compute exact result: 64.64 x 64.0 -> 128.64 fixed point */
+        mulu64(&val, &valh, val, mul);
+        mulu64(&valf, &tmp, valf, mul);
+        val += tmp;
+        valh += val < tmp;
+
+        /* Round 0.5 upward. */
+        tmp = valf >> 63;
+        val += tmp;
+        valh += val < tmp;
+
+        /* Report overflow. */
+        if (valh != 0) {
+            retval = -ERANGE;
+            goto out;
+        }
     }
-    *result = val * mul + (uint64_t) (fraction * mul);
+
+    *result = val;
     retval = 0;
 
 out:
-- 
2.20.1



  reply	other threads:[~2021-03-17  7:23 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-17  7:22 [PULL v2 00/15] misc fixes (strtoz, plugins, guest-loader) Alex Bennée
2021-03-17  7:22 ` Alex Bennée [this message]
2021-03-17 11:53   ` [PULL v2 01/15] utils: Use fixed-point arithmetic in qemu_strtosz Philippe Mathieu-Daudé
2021-03-17 12:13     ` Alex Bennée
2021-03-17 13:16       ` Philippe Mathieu-Daudé
2021-03-17 13:52         ` Eric Blake
2021-03-17 14:31         ` Alex Bennée
2021-03-17  7:22 ` [PULL v2 02/15] plugins: new syscalls plugin Alex Bennée
2021-03-17  7:22 ` [PULL v2 03/15] plugins: Expose physical addresses instead of device offsets Alex Bennée
2021-03-17  7:22 ` [PULL v2 04/15] plugins: expand kernel-doc for qemu_info_t Alex Bennée
2021-03-17  7:22 ` [PULL v2 05/15] plugins: cleanup kernel-doc for qemu_plugin_install Alex Bennée
2021-03-17  7:22 ` [PULL v2 06/15] plugins: expand the callback typedef kernel-docs Alex Bennée
2021-03-17  7:22 ` [PULL v2 07/15] plugins: expand the typedef kernel-docs for translation Alex Bennée
2021-03-17  7:22 ` [PULL v2 08/15] plugins: add qemu_plugin_cb_flags to kernel-doc Alex Bennée
2021-03-17  7:22 ` [PULL v2 09/15] plugins: add qemu_plugin_id_t " Alex Bennée
2021-03-17  7:22 ` [PULL v2 10/15] plugins: expand inline exec kernel-doc documentation Alex Bennée
2021-03-17  7:22 ` [PULL v2 11/15] plugins: expand kernel-doc for instruction query and instrumentation Alex Bennée
2021-03-17  7:22 ` [PULL v2 12/15] plugins: expand kernel-doc for memory " Alex Bennée
2021-03-17  7:22 ` [PULL v2 13/15] plugins: getting qemu_plugin_get_hwaddr only expose one function prototype Alex Bennée
2021-03-17  7:22 ` [PULL v2 14/15] plugins: Fixes typo in qemu-plugin.h Alex Bennée
2021-03-17  7:22 ` [PULL v2 15/15] hw/core: Only build guest-loader if libfdt is available Alex Bennée
2021-03-17 12:10   ` Philippe Mathieu-Daudé
2021-03-18 17:10 ` [PULL v2 00/15] misc fixes (strtoz, plugins, guest-loader) Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210317072216.16316-2-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.