summaryrefslogtreecommitdiff
path: root/src/cairo-output-stream.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2007-11-01 00:01:16 +1030
committerAdrian Johnson <ajohnson@redneon.com>2007-11-01 00:01:16 +1030
commitc37a8ace818770ce3f07c2a7147088231d559e44 (patch)
treec48c5b68630c504574555b3ede4bc4643f069adb /src/cairo-output-stream.c
parent8297daff896ca9d803959edb3c1955977594fab9 (diff)
downloadcairo-c37a8ace818770ce3f07c2a7147088231d559e44.tar.gz
Round floats in output-stream to 6 significant digits after decimal
The previous commit increased the precision of floats from 6 digits after the decimal point to 18 digits to correct rounding errors with very small numbers. However most of the time this extra precision is not required and results in increased PS/PDF output. This commit makes the precision after the decimal point 6 significant digits. For example: 1.234567 0.123456 0.00123456 0.00000000123456
Diffstat (limited to 'src/cairo-output-stream.c')
-rw-r--r--src/cairo-output-stream.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 6d9c733c9..b8fb706bf 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -215,6 +215,8 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
}
}
+#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
+
/* Format a double in a locale independent way and trim trailing
* zeros. Based on code from Alex Larson <alexl@redhat.com>.
* http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
@@ -231,18 +233,53 @@ _cairo_dtostr (char *buffer, size_t size, double d)
int decimal_point_len;
char *p;
int decimal_len;
+ int num_zeros, decimal_digits;
/* Omit the minus sign from negative zero. */
if (d == 0.0)
d = 0.0;
- snprintf (buffer, size, "%.18f", d);
-
locale_data = localeconv ();
decimal_point = locale_data->decimal_point;
decimal_point_len = strlen (decimal_point);
assert (decimal_point_len != 0);
+
+ /* Using "%f" to print numbers less than 0.1 will result in
+ * reduced precision due to the default 6 digits after the
+ * decimal point.
+ *
+ * For numbers is < 0.1, we print with maximum precision and count
+ * the number of zeros between the decimal point and the first
+ * significant digit. We then print the number again with the
+ * number of decimal places that gives us the required number of
+ * significant digits. This ensures the number is correctly
+ * rounded.
+ */
+ if (fabs (d) >= 0.1) {
+ snprintf (buffer, size, "%f", d);
+ } else {
+ snprintf (buffer, size, "%.18f", d);
+ p = buffer;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ while (isdigit (*p))
+ p++;
+
+ if (strncmp (p, decimal_point, decimal_point_len) == 0)
+ p += decimal_point_len;
+
+ num_zeros = 0;
+ while (*p++ == '0')
+ num_zeros++;
+
+ decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
+
+ if (decimal_digits < 18)
+ snprintf (buffer, size, "%.*f", decimal_digits, d);
+ }
p = buffer;
if (*p == '+' || *p == '-')