[goffice] dtoa: new implementation from musl.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] dtoa: new implementation from musl.
- Date: Fri, 4 Apr 2014 04:06:18 +0000 (UTC)
commit 9c301394fc1721a090dcd0f7c4914beddf35dbe6
Author: Morten Welinder <terra gnome org>
Date: Fri Apr 4 00:03:59 2014 -0400
dtoa: new implementation from musl.
This was adapted to implement round-ties-away-from-zero. (Aka biased
rounding.) This is a printf-style flag, so if need be we can make
it a compile setting.
ChangeLog | 6 +
NEWS | 2 +-
goffice/Makefile.am | 1 +
goffice/math/go-dtoa.c | 465 +++++++++++++++++++++++++++++++++++++++++++
goffice/math/go-dtoa.h | 17 ++
goffice/math/go-math.c | 174 ----------------
goffice/math/go-math.h | 6 +-
goffice/math/goffice-math.h | 1 +
goffice/utils/go-format.c | 50 +++---
9 files changed, 517 insertions(+), 205 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 72e2e14..debb2f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-04-04 Morten Welinder <terra gnome org>
+
+ * goffice/math/go-dtoa.c (go_dtoa): New function.
+
+ * goffice/utils/go-format.c: Use go_dtoa extensively.
+
2014-04-02 Morten Welinder <terra gnome org>
* goffice/utils/go-format.c (go_format_output_number_to_odf): Also
diff --git a/NEWS b/NEWS
index 7c8c1a0..bf8c9b7 100644
--- a/NEWS
+++ b/NEWS
@@ -8,8 +8,8 @@ Morten:
* Implement numbered colours in number formats.
* Fix plugin deactivation.
* Plug leaks.
- * New function go_ascii_dtoa.
* Fix rounding problem.
+ * Use musl code for dtoa. Adapt to round-ties-away-from-0.
--------------------------------------------------------------------------
goffice 0.10.13:
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index e4865eb..22ccda8 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -338,6 +338,7 @@ gtk_HEADERS = \
math_SOURCES = \
math/go-accumulator.c \
+ math/go-dtoa.c \
math/go-math.c \
math/go-rangefunc.c \
math/go-regression.c \
diff --git a/goffice/math/go-dtoa.c b/goffice/math/go-dtoa.c
new file mode 100644
index 0000000..58ad350
--- /dev/null
+++ b/goffice/math/go-dtoa.c
@@ -0,0 +1,465 @@
+/*
+ * go-dtoa.c: double-to-string conversion.
+ *
+ * Copyright 2014 Morten Welinder <terra gnome org>
+ *
+ *
+ *
+ * Large portions of this code was copied from http://www.musl-libc.org/
+ * under the following license:
+ *
+ * Copyright © 2005-2014 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/math/go-math.h>
+#include "go-dtoa.h"
+#include <string.h>
+#include <inttypes.h>
+#include <stdarg.h>
+
+typedef GString FAKE_FILE;
+
+/* musl code starts here */
+
+/* Some useful macros */
+
+#ifdef MUSL_ORIGINAL
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#endif
+#define CONCAT2(x,y) x ## y
+#define CONCAT(x,y) CONCAT2(x,y)
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM (1U<<('#'-' '))
+#define ZERO_PAD (1U<<('0'-' '))
+#define LEFT_ADJ (1U<<('-'-' '))
+#define PAD_POS (1U<<(' '-' '))
+#define MARK_POS (1U<<('+'-' '))
+#define GROUPED (1U<<('\''-' '))
+#ifdef MUSL_ORIGINAL
+#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
+#else
+#define FLAG_TIES_AWAY_0 (1U<<('"'-' '))
+#define FLAG_SHORTEST (1U<<('!'-' '))
+#define FLAG_TRUNCATE (1U<<('='-' '))
+#define FLAG_ASCII (1U<<(','-' '))
+#endif
+
+
+static void out(FAKE_FILE *f, const char *s, size_t l)
+{
+#ifdef MUSL_ORIGINAL
+ __fwritex((void *)s, l, f);
+#else
+ g_string_append_len (f, s, l);
+#endif
+}
+
+#ifndef MUSL_ORIGINAL
+static void
+outdecimal (FAKE_FILE *f, int fl)
+{
+ if (fl & FLAG_ASCII)
+ out(f, ".", 1);
+ else {
+ GString const *dec = go_locale_get_decimal();
+ out(f, dec->str, dec->len);
+ }
+}
+#endif
+
+
+static void pad(FAKE_FILE *f, char c, int w, int l, int fl)
+{
+ char pad[256];
+ if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
+ l = w - l;
+#ifdef MUSL_ORIGINAL
+ memset(pad, c, l>sizeof pad ? sizeof pad : l);
+ for (; l >= sizeof pad; l -= sizeof pad)
+ out(f, pad, sizeof pad);
+#else
+ /* Just kill some warnings */
+ memset(pad, c, (size_t)l>sizeof pad ? sizeof pad : (size_t)l);
+ for (; (size_t)l >= sizeof pad; l -= sizeof pad)
+ out(f, pad, sizeof pad);
+#endif
+ out(f, pad, l);
+}
+
+static const char xdigits[16] = {
+ "0123456789ABCDEF"
+};
+
+static char *fmt_u(uintmax_t x, char *s)
+{
+ unsigned long y;
+ for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
+ for (y=x; y; y/=10) *--s = '0' + y%10;
+ return s;
+}
+
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+
+static int fmt_fp(FAKE_FILE *f, long double y, int w, int p, int fl, int t)
+{
+ uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
+ uint32_t *a, *d, *r, *z;
+#ifdef MUSL_ORIGINAL
+ int e2=0, e, i, j, l;
+#else
+ /* Make i unsigned kills some warnings */
+ int e2=0, e, j, l;
+ unsigned i;
+#endif
+ char buf[9+LDBL_MANT_DIG/4], *s;
+ const char *prefix="-0X+0X 0X-0x+0x 0x";
+ int pl;
+ char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
+
+#ifndef MUSL_ORIGINAL
+ if (fl & FLAG_TRUNCATE) g_string_truncate (f, 0);
+#endif
+
+ pl=1;
+ if (signbit(y)) {
+ y=-y;
+ } else if (fl & MARK_POS) {
+ prefix+=3;
+ } else if (fl & PAD_POS) {
+ prefix+=6;
+ } else prefix++, pl=0;
+
+ if (!go_finitel(y)) {
+ const char *s = (t&32)?"inf":"INF";
+ if (y!=y) s=(t&32)?"nan":"NAN", pl=0;
+ pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
+ out(f, prefix, pl);
+ out(f, s, 3);
+ pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
+ return MAX(w, 3+pl);
+ }
+
+ y = frexpl(y, &e2) * 2;
+ if (y) e2--;
+
+ if ((t|32)=='a') {
+ long double round = 8.0;
+ int re;
+
+ if (t&32) prefix += 9;
+ pl += 2;
+
+ if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+ else re=LDBL_MANT_DIG/4-1-p;
+
+ if (re) {
+ while (re--) round*=16;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ } else {
+ y+=round;
+ y-=round;
+ }
+ }
+
+ estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
+ if (estr==ebuf) *--estr='0';
+ *--estr = (e2<0 ? '-' : '+');
+ *--estr = t+('p'-'a');
+
+ s=buf;
+ do {
+ int x=y;
+ *s++=xdigits[x]|(t&32);
+ y=16*(y-x);
+ if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+ } while (y);
+
+ if (p && s-buf-2 < p)
+ l = (p+2) + (ebuf-estr);
+ else
+ l = (s-buf) + (ebuf-estr);
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+ out(f, buf, s-buf);
+ pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
+ out(f, estr, ebuf-estr);
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+ return MAX(w, pl+l);
+ }
+ if (p<0) p=6;
+
+ if (y) y *= 0x1p28, e2-=28;
+
+ if (e2<0) a=r=z=big;
+ else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+ do {
+ *z = y;
+ y = 1000000000*(y-*z++);
+ } while (y);
+
+ while (e2>0) {
+ uint32_t carry=0;
+ int sh=MIN(29,e2);
+ for (d=z-1; d>=a; d--) {
+ uint64_t x = ((uint64_t)*d<<sh)+carry;
+ *d = x % 1000000000;
+ carry = x / 1000000000;
+ }
+ if (!z[-1] && z>a) z--;
+ if (carry) *--a = carry;
+ e2-=sh;
+ }
+ while (e2<0) {
+ uint32_t carry=0, *b;
+ int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9;
+ for (d=a; d<z; d++) {
+ uint32_t rm = *d & ((1<<sh)-1);
+ *d = (*d>>sh) + carry;
+ carry = (1000000000>>sh) * rm;
+ }
+ if (!*a) a++;
+ if (carry) *z++ = carry;
+ /* Avoid (slow!) computation past requested precision */
+ b = (t|32)=='f' ? r : a;
+ if (z-b > need) z = b+need;
+ e2+=sh;
+ }
+
+ if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ else e=0;
+
+ /* Perform rounding: j is precision after the radix (possibly neg) */
+ j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
+ if (j < 9*(z-r-1)) {
+ uint32_t x;
+ /* We avoid C's broken division of negative numbers */
+ d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
+ j += 9*LDBL_MAX_EXP;
+ j %= 9;
+ for (i=10, j++; j<9; i*=10, j++);
+ x = *d % i;
+ /* Are there any significant digits past j? */
+ if (x || d+1!=z) {
+ long double round = CONCAT(0x1p,LDBL_MANT_DIG);
+ long double small;
+#ifdef MUSL_ORIGINAL
+ if (*d/i & 1) round += 2;
+#else
+ /*
+ * For ties-away-from-zero, just pretend we have
+ * an odd digit.
+ */
+ if ((fl & FLAG_TIES_AWAY_0) || (*d/i & 1)) round += 2;
+#endif
+ if (x<i/2) small=0x0.8p0;
+ else if (x==i/2 && d+1==z) small=0x1.0p0;
+ else small=0x1.8p0;
+ if (pl && *prefix=='-') round*=-1, small*=-1;
+ *d -= x;
+ /* Decide whether to round by probing round+small */
+ if (round+small != round) {
+ *d = *d + i;
+ while (*d > 999999999) {
+ *d--=0;
+ (*d)++;
+ }
+ if (d<a) a=d;
+ for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ }
+ }
+ if (z>d+1) z=d+1;
+ for (; !z[-1] && z>a; z--);
+ }
+
+ if ((t|32)=='g') {
+ if (!p) p++;
+ if (p>e && e>=-4) {
+ t--;
+ p-=e+1;
+ } else {
+ t-=2;
+ p--;
+ }
+ if (!(fl&ALT_FORM)) {
+ /* Count trailing zeros in last place */
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ else j=9;
+ if ((t|32)=='f')
+ p = MIN(p,MAX(0,9*(z-r-1)-j));
+ else
+ p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ }
+ }
+ l = 1 + p + (p || (fl&ALT_FORM));
+ if ((t|32)=='f') {
+ if (e>0) l+=e;
+ } else {
+ estr=fmt_u(e<0 ? -e : e, ebuf);
+ while(ebuf-estr<2) *--estr='0';
+ *--estr = (e<0 ? '-' : '+');
+ *--estr = t;
+ l += ebuf-estr;
+ }
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+
+ if ((t|32)=='f') {
+ if (a>r) a=r;
+ for (d=a; d<=r; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (d!=a) while (s>buf) *--s='0';
+ else if (s==buf+9) *--s='0';
+ out(f, s, buf+9-s);
+ }
+#ifdef MUSL_ORIGINAL
+ if (p || (fl&ALT_FORM)) out(f, ".", 1);
+#else
+ if (p || (fl&ALT_FORM)) outdecimal(f, fl);
+#endif
+ for (; d<z && p>0; d++, p-=9) {
+ char *s = fmt_u(*d, buf+9);
+ while (s>buf) *--s='0';
+ out(f, s, MIN(9,p));
+ }
+ pad(f, '0', p+9, 9, 0);
+ } else {
+ if (z<=a) z=a+1;
+ for (d=a; d<z && p>=0; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (s==buf+9) *--s='0';
+ if (d!=a) while (s>buf) *--s='0';
+ else {
+ out(f, s++, 1);
+#ifdef MUSL_ORIGINAL
+ if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
+#else
+ if (p>0||(fl&ALT_FORM)) outdecimal(f, fl);
+#endif
+ }
+ out(f, s, MIN(buf+9-s, p));
+ p -= buf+9-s;
+ }
+ pad(f, '0', p+18, 18, 0);
+ out(f, estr, ebuf-estr);
+ }
+
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+
+ return MAX(w, pl+l);
+}
+
+/* musl code ends here */
+
+static void
+parse_fmt (const char *fmt, va_list args,
+ int *w, int *p, int *fl, int *t, long double *d)
+{
+ gboolean is_long = FALSE;
+
+ *w = 1;
+ *p = -1;
+ *fl = 0;
+ *d = 0;
+ *t = 'g';
+
+ while (1) {
+ switch (*fmt) {
+ case '0': *fl |= ZERO_PAD; fmt++; continue;
+ case '^': *fl |= FLAG_TIES_AWAY_0; fmt++; continue;
+ case '+': *fl |= MARK_POS; fmt++; continue;
+ case '-': *fl |= LEFT_ADJ; fmt++; continue;
+ case '!': *fl |= FLAG_SHORTEST; fmt++; continue;
+ case '=': *fl |= FLAG_TRUNCATE; fmt++; continue;
+ case ',': *fl |= FLAG_ASCII; fmt++; continue;
+ }
+ break;
+ }
+
+ while (g_ascii_isdigit (*fmt))
+ *w = *w * 10 + (*fmt++ - '0');
+
+ if (*fmt == '.') {
+ if (fmt[1] == '*') {
+ fmt += 2;
+ *p = va_arg (args, int);
+ } else {
+ *p = 0;
+ fmt++;
+ while (g_ascii_isdigit (*fmt))
+ *p = *p * 10 + (*fmt++ - '0');
+ }
+ }
+
+ if (*fmt == 'L') {
+ is_long = TRUE;
+ fmt++;
+ }
+
+ if (!strchr ("efgaEFGA", *fmt))
+ return;
+ *t = *fmt;
+
+ if (is_long)
+ *d = va_arg (args, long double);
+ else
+ *d = va_arg (args, double);
+}
+
+
+
+void
+go_dtoa (GString *dst, const char *fmt, ...)
+{
+ int w, p, fl, t;
+ va_list args;
+ long double d;
+ gboolean debug = FALSE;
+
+ va_start (args, fmt);
+ parse_fmt (fmt, args, &w, &p, &fl, &t, &d);
+ va_end (args);
+
+ if (fl & FLAG_SHORTEST) p = 17;
+ if (debug) g_printerr ("%Lg [%s] t=%c p=%d\n", d, fmt, t, p);
+ fmt_fp (dst, d, w, p, fl, t);
+ if (debug) g_printerr (" --> %s\n", dst->str);
+}
diff --git a/goffice/math/go-dtoa.h b/goffice/math/go-dtoa.h
new file mode 100644
index 0000000..24f80b1
--- /dev/null
+++ b/goffice/math/go-dtoa.h
@@ -0,0 +1,17 @@
+#ifndef GO_DTOA_H__
+#define GO_DTOA_H__
+
+#include <goffice/goffice-features.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* ------------------------------------------------------------------------- */
+
+void go_dtoa (GString *dst, const char *fmt, ...);
+
+/* ------------------------------------------------------------------------- */
+
+G_END_DECLS
+
+#endif /* GO_DTOA_H__ */
diff --git a/goffice/math/go-math.c b/goffice/math/go-math.c
index 5fc01a4..d568e1a 100644
--- a/goffice/math/go-math.c
+++ b/goffice/math/go-math.c
@@ -452,180 +452,6 @@ go_ascii_strtod (const char *s, char **end)
return res;
}
-static void
-go_ascii_dtoa_fmt_helper (char *buf, size_t bufsiz, char fmt,
- double d, int prec)
-{
- char fmtstr[8], *p = fmtstr;
-
- *p++ = '%';
- *p++ = '.';
- if (prec >= 10) *p++ = '0' + (prec / 10);
- *p++ = '0' + (prec % 10);
- *p++ = fmt;
- *p = 0;
-
- g_ascii_formatd (buf, bufsiz, fmtstr, d);
-}
-
-/**
- * go_ascii_dtoa:
- * @d: value to convert
- * @fmt: printf-style format specified; 'e', 'E', or 'g'.
- *
- * Returns: (transfer full): a string that when converted back into a floating-
- * point value will produce @d. This function will use '.' and decimal
- * point.
- *
- * The resulting string is not necessarily the shortest possible, but some
- * care is put into avoiding needless ...0003 and ...9998 endings.
- */
-char *
-go_ascii_dtoa (double d, char fmt)
-{
- char buf[128];
- char *epos;
- gboolean enotation;
- static int prec;
-
- if (!prec) {
- double l10 = log10 (FLT_RADIX);
- prec = (int)ceil (DBL_MANT_DIG * l10) + (l10 != (int)l10);
- g_assert (prec >= 11 && prec <= 99);
- }
-
- if (!go_finite (d)) {
- if (d > 0)
- return g_strdup ("+inf");
- if (d < 0)
- return g_strdup ("-inf");
- return g_strdup ("nan");
- }
-
- if (fabs (d) >= 1e16 || (d != 0 && fabs (d) < 1e-4))
- fmt = g_ascii_islower (fmt) ? 'e' : 'E';
- enotation = g_ascii_tolower (fmt) == 'e';
-
- /* e-notation counts digits after the decimal point. */
- if (enotation)
- prec--;
-
- go_ascii_dtoa_fmt_helper (buf, 128, fmt, d, prec);
- epos = (enotation ? strchr (buf, fmt) : buf + strlen (buf));
- if (epos[-1] == '0') {
- /* Nothing */
- } else if ((epos[-1] <= '5' && epos[-2] == '0' && epos[-3] == '0') ||
- (epos[-1] >= '5' && epos[-2] == '9' && epos[-3] == '9')) {
- char bufm1[128];
- go_ascii_dtoa_fmt_helper (bufm1, 128, fmt, d, prec - 1);
- if (go_ascii_strtod (bufm1, NULL) == d) {
- strcpy (buf, bufm1);
- epos = (enotation ? strchr (buf, fmt) : buf + strlen (buf));
- }
- }
-
- if (epos[-1] == '0' && strchr (buf, '.')) {
- char *p = epos;
- while (p[-1] == '0') p--;
- if (p[-1] == '.') p--;
- memmove (p, epos, strlen (epos) + 1);
- }
-
- return g_strdup (buf);
-}
-
-
-#ifdef GOFFICE_WITH_LONG_DOUBLE
-
-static void
-go_ascii_ldtoa_fmt_helper (char *buf, size_t bufsiz, char fmt,
- long double d, int prec)
-{
- char fmtstr[8], *p = fmtstr;
- char *old_locale;
-
- *p++ = '%';
- *p++ = '.';
- if (prec >= 10) *p++ = '0' + (prec / 10);
- *p++ = '0' + (prec % 10);
- *p++ = fmt;
- *p = 0;
-
- /* Just use setlocale and hope for the best. */
- old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
- g_snprintf (buf, bufsiz, fmtstr, d);
- setlocale (LC_NUMERIC, old_locale);
- g_free (old_locale);
-}
-
-
-/**
- * go_ascii_ldtoa:
- * @d: value to convert
- * @fmt: printf-style format specified; 'e', 'E', or 'g'.
- *
- * Returns: (transfer full): a string that when converted back into a floating-
- * point value will produce @d. This function will use '.' and decimal
- * point.
- *
- * The resulting string is not necessarily the shortest possible, but some
- * care is put into avoiding needless ...0003 and ...9998 endings.
- */
-char *
-go_ascii_ldtoa (long double d, char fmt)
-{
- char buf[128];
- char *epos;
- gboolean enotation;
- static int prec;
-
- if (!prec) {
- double l10 = log10 (FLT_RADIX);
- prec = (int)ceil (LDBL_MANT_DIG * l10) + (l10 != (int)l10);
- g_assert (prec >= 11 && prec <= 99);
- }
-
- if (!go_finitel (d)) {
- if (d > 0)
- return g_strdup ("+inf");
- if (d < 0)
- return g_strdup ("-inf");
- return g_strdup ("nan");
- }
-
- if (fabsl (d) >= 1e16 || (d != 0 && fabsl (d) < 1e-4))
- fmt = g_ascii_islower (fmt) ? 'e' : 'E';
- enotation = g_ascii_tolower (fmt) == 'e';
-
- /* e-notation counts digits after the decimal point. */
- if (enotation)
- prec--;
-
- go_ascii_ldtoa_fmt_helper (buf, 128, fmt, d, prec);
- epos = (enotation ? strchr (buf, fmt) : buf + strlen (buf));
- if (epos[-1] == '0') {
- /* Nothing */
- } else if ((epos[-1] <= '5' && epos[-2] == '0' && epos[-3] == '0') ||
- (epos[-1] >= '5' && epos[-2] == '9' && epos[-3] == '9')) {
- char bufm1[128];
- go_ascii_ldtoa_fmt_helper (bufm1, 128, fmt, d, prec - 1);
- if (go_ascii_strtold (bufm1, NULL) == d) {
- strcpy (buf, bufm1);
- epos = (enotation ? strchr (buf, fmt) : buf + strlen (buf));
- }
- }
-
- if (epos[-1] == '0' && strchr (buf, '.')) {
- char *p = epos;
- while (p[-1] == '0') p--;
- if (p[-1] == '.') p--;
- memmove (p, epos, strlen (epos) + 1);
- }
-
- return g_strdup (buf);
-}
-#endif
-
#ifdef GOFFICE_SUPPLIED_LOG1P
double
diff --git a/goffice/math/go-math.h b/goffice/math/go-math.h
index 5a05fbc..84f2c94 100644
--- a/goffice/math/go-math.h
+++ b/goffice/math/go-math.h
@@ -1,8 +1,8 @@
#ifndef __GO_MATH_H
#define __GO_MATH_H
-#include <math.h>
#include <goffice/goffice-features.h>
+#include <math.h>
#include <glib.h>
#include <goffice/goffice.h>
@@ -39,8 +39,6 @@ double go_pow10 (int n);
double go_strtod (const char *s, char **end);
double go_ascii_strtod (const char *s, char **end);
-char *go_ascii_dtoa (double d, char fmt);
-
double go_sinpi (double x);
double go_cospi (double x);
double go_tanpi (double x);
@@ -87,8 +85,6 @@ long double go_pow10l (int n);
long double go_strtold (const char *s, char **end);
long double go_ascii_strtold (const char *s, char **end);
-char *go_ascii_ldtoa (long double d, char fmt);
-
long double go_sinpil (long double x);
long double go_cospil (long double x);
long double go_tanpil (long double x);
diff --git a/goffice/math/goffice-math.h b/goffice/math/goffice-math.h
index b9fd172..519afbe 100644
--- a/goffice/math/goffice-math.h
+++ b/goffice/math/goffice-math.h
@@ -18,6 +18,7 @@ typedef struct GOQuadQRl_ GOQuadQRl;
#include <goffice/math/go-complex.h>
#include <goffice/math/go-cspline.h>
#include <goffice/math/go-distribution.h>
+#include <goffice/math/go-dtoa.h>
#include <goffice/math/go-fft.h>
#include <goffice/math/go-math.h>
#include <goffice/math/go-matrix.h>
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index 41b4858..09a39e0 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -2856,7 +2856,7 @@ SUFFIX(printf_engineering) (GString *dst, DOUBLE val, int n, int wd)
const GString *decimal = go_locale_get_decimal ();
if (wd <= 1 || val == 0 || !SUFFIX(go_finite) (val)) {
- g_string_printf (dst, "%.*" FORMAT_E, n, val);
+ go_dtoa (dst, "=^.*" FORMAT_E, n, val);
return;
}
@@ -2866,7 +2866,7 @@ SUFFIX(printf_engineering) (GString *dst, DOUBLE val, int n, int wd)
? exponent_guess % wd
: (wd - ((-exponent_guess) % wd)) % wd;
- g_string_printf (dst, "%.*" FORMAT_E, n + nde, val);
+ go_dtoa (dst, "=^.*" FORMAT_E, n + nde, val);
epos = (char *)strchr (dst->str, 'E');
if (!epos)
return;
@@ -4202,7 +4202,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
const char *dot;
if (!numtxt)
numtxt = g_string_sized_new (100);
- g_string_printf (numtxt, "%.*" FORMAT_f, n, val);
+ go_dtoa (numtxt, "=^.*" FORMAT_f, n, val);
dot = strstr (numtxt->str, decimal->str);
handle_chinese (numtxt, &dot,
numeral_shape, shape_flags);
@@ -4797,6 +4797,9 @@ go_format_measure_strlen (const GString *str,
static void
drop_zeroes (GString *str, int *prec)
{
+ if (*prec == 0)
+ return;
+
while (str->str[str->len - 1] == '0') {
g_string_truncate (str, str->len - 1);
(*prec)--;
@@ -4925,7 +4928,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
g_print ("Room for whole part.\n");
#endif
if (val == SUFFIX(floor) (val) || digs_as_int == maxdigits) {
- g_string_printf (str, "%.0" FORMAT_f, val);
+ go_dtoa (str, "=^.0" FORMAT_f, val);
HANDLE_NUMERAL_SHAPE;
HANDLE_SIGN (0);
SETUP_LAYOUT;
@@ -4937,7 +4940,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
g_print ("Maybe room for whole part.\n");
#endif
- g_string_printf (str, "%.0" FORMAT_f, val);
+ go_dtoa (str, "=^.0" FORMAT_f, val);
HANDLE_NUMERAL_SHAPE;
HANDLE_SIGN (0);
SETUP_LAYOUT;
@@ -4950,10 +4953,10 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
}
/* Number of digits in [aval]. */
- digs = (aval >= 1 ? 1 + SUFFIX(ilog10) (aval) : 1);
+ digs = (aval >= 10 ? 1 + SUFFIX(ilog10) (aval) : 1);
prec = maxdigits - digs;
- g_string_printf (str, "%.*" FORMAT_f, prec, val);
+ go_dtoa (str, "=^.*" FORMAT_f, prec, val);
if (check_val) {
/*
* We're not width-limited; we may have to increase maxdigits
@@ -4961,7 +4964,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
*/
if (val != STRTO(str->str, NULL)) {
maxdigits++, prec++;
- g_string_printf (str, "%.*" FORMAT_f, prec, val);
+ go_dtoa (str, "=^.*" FORMAT_f, prec, val);
}
}
HANDLE_NUMERAL_SHAPE;
@@ -4977,7 +4980,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
return;
prec--;
- g_string_printf (str, "%.*" FORMAT_f, prec, val);
+ go_dtoa (str, "=^.*" FORMAT_f, prec, val);
drop_zeroes (str, &prec);
HANDLE_NUMERAL_SHAPE;
HANDLE_SIGN (0);
@@ -5003,7 +5006,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
if (prec == 0 || !rounds_to_0) {
int w;
- g_string_printf (str, "%.0" FORMAT_E, val);
+ go_dtoa (str, "=^.0" FORMAT_E, val);
HANDLE_NUMERAL_SHAPE;
HANDLE_SIGN (0);
epos = strchr (str->str, 'E') - str->str;
@@ -5020,7 +5023,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
goto zero;
}
prec = MIN (prec, PREFIX(DIG) - 1);
- g_string_printf (str, "%.*" FORMAT_E, prec, val);
+ go_dtoa (str, "=^.*" FORMAT_E, prec, val);
epos = strchr (str->str, 'E') - str->str;
digs = 0;
while (str->str[epos - 1 - digs] == '0')
@@ -5054,7 +5057,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
if (prec < 0)
break;
}
- g_string_printf (str, "%.*" FORMAT_E, prec, val);
+ go_dtoa (str, "=^.*" FORMAT_E, prec, val);
}
if (rounds_to_0)
@@ -7508,7 +7511,7 @@ char *
go_format_odf_style_map (GOFormat const *fmt, int cond_part)
{
char const *format_string;
- char *res, *valstr;
+ GString *valstr;
g_return_val_if_fail (fmt != NULL, NULL);
g_return_val_if_fail (fmt->typ == GO_FMT_COND, NULL);
@@ -7541,11 +7544,9 @@ go_format_odf_style_map (GOFormat const *fmt, int cond_part)
return NULL;
}
- valstr = go_ascii_dtoa (fmt->u.cond.conditions[cond_part].val, 'g');
- res = g_strconcat (format_string, valstr, NULL);
- g_free (valstr);
-
- return res;
+ valstr = g_string_new (format_string);
+ go_dtoa (valstr, "!g", fmt->u.cond.conditions[cond_part].val);
+ return g_string_free (valstr, FALSE);
}
#endif
@@ -8931,9 +8932,8 @@ go_format_output_conditional_to_odf (GsfXMLOut *xout, gboolean with_extension,
GOFormatCondition const *cond = &fmt->u.cond.conditions[i];
const char *oper = NULL;
double val = cond->val;
- char *valstr;
char *partname;
- char *condition;
+ GString *condition;
if (i == defi)
continue;
@@ -8955,17 +8955,17 @@ go_format_output_conditional_to_odf (GsfXMLOut *xout, gboolean with_extension,
partname = g_strdup_printf ("%s-%d", name, i);
- valstr = go_ascii_dtoa (val, 'g');
- condition = g_strdup_printf ("value()%s%s", oper, valstr);
- g_free (valstr);
+ condition = g_string_new ("value()");
+ g_string_append (condition, oper);
+ go_dtoa (condition, "!g", val);
gsf_xml_out_start_element (xout, STYLE "map");
- gsf_xml_out_add_cstr (xout, STYLE "condition", condition);
+ gsf_xml_out_add_cstr (xout, STYLE "condition", condition->str);
gsf_xml_out_add_cstr (xout, STYLE "apply-style-name", partname);
gsf_xml_out_end_element (xout); /* </style:map> */
g_free (partname);
- g_free (condition);
+ g_string_free (condition, TRUE);
}
/* Do we need to add a catch-all General? */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]