]> granicus.if.org Git - graphviz/commitdiff
specialize and accelerate gv_trim_zeros
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 15 May 2021 15:58:05 +0000 (08:58 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 27 May 2021 03:26:36 +0000 (20:26 -0700)
This function trims unnecessary trailing zeros from a printed floating-point
number. It was written to be extremely general, however it is only ever used to
trim a number printed with the format string "%.02f". We can take advantage of
this fact to know that, if it can locate a period, there are exactly two digits
following this that need to be checked. This then allows implementing the
remainder of the function not as a loop but as simply a few branches.

Using tests/regression_tests/large/long_chain, which has been used for other
profiling in this area, this drops total executed instructions from 8160952787
to 8143275099, a speed up of ~2%.

lib/gvc/gvdevice.c

index a65d0e5a1547102e985d73557e0234a7ade72406..93efce34252aed63a627d880b33cd6734e47ad5d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "config.h"
 
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -524,22 +525,25 @@ int main (int argc, char *argv[])
 
 /* gv_trim_zeros
 * Trailing zeros are removed and decimal point, if possible.
+* Assumes the input is the result of %.02f printing.
 */
 static void gv_trim_zeros(char* buf)
 {
-    char* dotp;
-    char* p;
-
-    if ((dotp = strchr(buf, '.'))) {
-        p = dotp + 1;
-        while (*p) p++;  // find end of string
-        p--;
-        while (*p == '0') *p-- = '\0';
-        if (*p == '.')        // If all decimals were zeros, remove ".".
-            *p = '\0';
-        else
-            p++;
+  char *dotp = strchr(buf, '.');
+  if (dotp == NULL) {
+    return;
+  }
+
+  // check this really is the result of %.02f printing
+  assert(isdigit(dotp[1]) && isdigit(dotp[2]) && dotp[3] == '\0');
+
+  if (dotp[2] == '0') {
+    if (dotp[1] == '0') {
+      *dotp = '\0';
+    } else {
+      dotp[2] = '\0';
     }
+  }
 }
 
 void gvprintdouble(GVJ_t * job, double num)