summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2015-03-09 00:21:26 +0100
committerRobin Watts <robin.watts@artifex.com>2015-03-20 17:14:09 +0000
commite027621812dadd741d6025ebbdafd0d65e01b9e2 (patch)
tree3aae7e4d139f2726ba6f2d2176a876b8d6be207b /source
parent412cccf2fdec282a4cc1345c551808e6a257dbdd (diff)
downloadmupdf-e027621812dadd741d6025ebbdafd0d65e01b9e2.tar.xz
Workaround bug in ftoa.
Diffstat (limited to 'source')
-rw-r--r--source/fitz/ftoa.c332
1 files changed, 22 insertions, 310 deletions
diff --git a/source/fitz/ftoa.c b/source/fitz/ftoa.c
index 355f0879..92ee9edf 100644
--- a/source/fitz/ftoa.c
+++ b/source/fitz/ftoa.c
@@ -1,178 +1,5 @@
-/* The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
#include "mupdf/fitz.h"
-#include <stdio.h>
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#ifndef INFINITY
-#define INFINITY (DBL_MAX+DBL_MAX)
-#endif
-#ifndef NAN
-#define NAN (INFINITY-INFINITY)
-#endif
-
-#ifndef DEFINED_ULONG
-#define DEFINED_ULONG
-typedef unsigned long ulong;
-#endif
-
-enum { NSIGNIF = 9 };
-
-/*
- * first few powers of 10
- */
-static float pows10[] =
-{
- 1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f, 1e7f, 1e8f, 1e9f,
- 1e10f, 1e11f, 1e12f, 1e13f, 1e14f, 1e15f, 1e16f, 1e17f, 1e18f, 1e19f,
- 1e20f, 1e21f, 1e22f, 1e23f, 1e24f, 1e25f, 1e26f, 1e27f, 1e28f, 1e29f,
- 1e30f, 1e31f, 1e32f, 1e33f, 1e34f, 1e35f, 1e36f, 1e37f, 1e38f
-};
-#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
-#define pow10(x) fmtpow10(x)
-
-static float
-pow10(int n)
-{
- float d;
- int neg;
-
- neg = 0;
- if(n < 0){
- neg = 1;
- n = -n;
- }
-
- if(n < npows10)
- d = pows10[n];
- else{
- d = pows10[npows10-1];
- for(;;){
- n -= npows10 - 1;
- if(n < npows10){
- d *= pows10[n];
- break;
- }
- d *= pows10[npows10 - 1];
- }
- }
- if(neg)
- return 1./d;
- return d;
-}
-
-/*
- * add 1 to the decimal integer string a of length n.
- * if 99999 overflows into 10000, return 1 to tell caller
- * to move the virtual decimal point.
- */
-static int
-xadd1(char *a, int n)
-{
- char *b;
- int c;
-
- if(n < 0 || n > NSIGNIF)
- return 0;
- for(b = a+n-1; b >= a; b--) {
- c = *b + 1;
- if(c <= '9') {
- *b = c;
- return 0;
- }
- *b = '0';
- }
- /*
- * need to overflow adding digit.
- * shift number down and insert 1 at beginning.
- * decimal is known to be 0s or we wouldn't
- * have gotten this far. (e.g., 99999+1 => 00000)
- */
- a[0] = '1';
- return 1;
-}
-
-/*
- * subtract 1 from the decimal integer string a.
- * if 10000 underflows into 09999, make it 99999
- * and return 1 to tell caller to move the virtual
- * decimal point. this way, xsub1 is inverse of xadd1.
- */
-static int
-xsub1(char *a, int n)
-{
- char *b;
- int c;
-
- if(n < 0 || n > NSIGNIF)
- return 0;
- for(b = a+n-1; b >= a; b--) {
- c = *b - 1;
- if(c >= '0') {
- if(c == '0' && b == a) {
- /*
- * just zeroed the top digit; shift everyone up.
- * decimal is known to be 9s or we wouldn't
- * have gotten this far. (e.g., 10000-1 => 09999)
- */
- *b = '9';
- return 1;
- }
- *b = c;
- return 0;
- }
- *b = '9';
- }
- /*
- * can't get here. the number a is always normalized
- * so that it has a nonzero first digit.
- */
- return 0;
-}
-
-/*
- * format exponent like sprintf(p, "e%+d", e)
- */
-static void
-fmtexp(char *p, int e)
-{
- char se[9];
- int i;
-
- *p++ = 'e';
- if(e < 0) {
- *p++ = '-';
- e = -e;
- } else
- *p++ = '+';
- i = 0;
- while(e) {
- se[i++] = e % 10 + '0';
- e /= 10;
- }
- while(i < 1)
- se[i++] = '0';
- while(i > 0)
- *p++ = se[--i];
- *p++ = '\0';
-}
-
/*
* compute decimal integer m, exp such that:
* f = m*10^exp
@@ -182,149 +9,34 @@ fmtexp(char *p, int e)
void
fz_ftoa(float f, char *s, int *exp, int *neg, int *ns)
{
- int c, d, e2, e, ee, i, ndigit, oerrno;
- char tmp[NSIGNIF+10];
- float g;
-
- oerrno = errno; /* in case strtod smashes errno */
-
- /*
- * make f non-negative.
- */
- *neg = 0;
- if(f < 0) {
- f = -f;
- *neg = 1;
- }
-
- /*
- * must handle zero specially.
- */
- if(f == 0){
- *exp = 0;
- s[0] = '0';
- s[1] = '\0';
- *ns = 1;
- return;
- }
-
- /*
- * find g,e such that f = g*10^e.
- * guess 10-exponent using 2-exponent, then fine tune.
- */
- frexpf(f, &e2);
- e = (int)(e2 * .301029995664f);
- g = f * pow10(-e);
- while(g < 1) {
- e--;
- g = f * pow10(-e);
- }
- while(g >= 10) {
- e++;
- g = f * pow10(-e);
- }
-
- /*
- * convert NSIGNIF digits as a first approximation.
- */
- for(i=0; i<NSIGNIF; i++) {
- d = (int)g;
- s[i] = d+'0';
- g = (g-d) * 10;
- }
- s[i] = 0;
-
- /*
- * adjust e because s is 314159... not 3.14159...
- */
- e -= NSIGNIF-1;
- fmtexp(s+NSIGNIF, e);
-
- /*
- * adjust conversion until strtod(s) == f exactly.
- */
- for(i=0; i<10; i++) {
- g = fz_strtod(s, NULL);
- if(f > g) {
- if(xadd1(s, NSIGNIF)) {
- /* gained a digit */
- e--;
- fmtexp(s+NSIGNIF, e);
- }
- continue;
- }
- if(f < g) {
- if(xsub1(s, NSIGNIF)) {
- /* lost a digit */
- e++;
- fmtexp(s+NSIGNIF, e);
- }
- continue;
- }
- break;
- }
-
- /*
- * play with the decimal to try to simplify.
- */
+ char buf[40], *p = buf;
+ int i;
- /*
- * bump last few digits up to 9 if we can
- */
- for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
- c = s[i];
- if(c != '9') {
- s[i] = '9';
- g = fz_strtod(s, NULL);
- if(g != f) {
- s[i] = c;
- break;
- }
- }
+ for (i = 0; i < 10; ++i)
+ {
+ sprintf(buf, "%.*e", i, f);
+ if (fz_atof(buf) == f)
+ break;
}
- /*
- * add 1 in hopes of turning 9s to 0s
- */
- if(s[NSIGNIF-1] == '9') {
- strcpy(tmp, s);
- ee = e;
- if(xadd1(tmp, NSIGNIF)) {
- ee--;
- fmtexp(tmp+NSIGNIF, ee);
- }
- g = fz_strtod(tmp, NULL);
- if(g == f) {
- strcpy(s, tmp);
- e = ee;
- }
+ if (*p == '-')
+ {
+ *neg = 1;
+ ++p;
}
+ else
+ *neg = 0;
- /*
- * bump last few digits down to 0 as we can.
- */
- for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
- c = s[i];
- if(c != '0') {
- s[i] = '0';
- g = fz_strtod(s, NULL);
- if(g != f) {
- s[i] = c;
- break;
- }
+ *ns = 0;
+ while (*p && *p != 'e')
+ {
+ if (*p >= '0' && *p <= '9')
+ {
+ *ns += 1;
+ *s++ = *p;
}
+ ++p;
}
- /*
- * remove trailing zeros.
- */
- ndigit = NSIGNIF;
- while(ndigit > 1 && s[ndigit-1] == '0'){
- e++;
- --ndigit;
- }
- s[ndigit] = 0;
- *exp = e;
- *ns = ndigit;
- errno = oerrno;
+ *exp = fz_atoi(p+1) - (*ns) + 1;
}