7 // The maximum number of significant (decimal!) figures in an IEEE
11 static int tonum(unsigned char* s, int len, double* result);
12 static int fromnum(double val, unsigned char* s);
14 int naStr_len(naRef s)
16 if(!IS_STR(s)) return 0;
17 return s.ref.ptr.str->len;
20 char* naStr_data(naRef s)
22 if(!IS_STR(s)) return 0;
23 return (char*)s.ref.ptr.str->data;
26 static void setlen(struct naStr* s, int sz)
28 if(s->data) naFree(s->data);
30 s->data = naAlloc(sz+1);
31 s->data[sz] = 0; // nul terminate
34 naRef naStr_buf(naRef dst, int len)
36 setlen(dst.ref.ptr.str, len);
37 naBZero(dst.ref.ptr.str->data, len);
41 naRef naStr_fromdata(naRef dst, char* data, int len)
43 if(!IS_STR(dst)) return naNil();
44 setlen(dst.ref.ptr.str, len);
45 memcpy(dst.ref.ptr.str->data, data, len);
49 naRef naStr_concat(naRef dest, naRef s1, naRef s2)
51 struct naStr* dst = dest.ref.ptr.str;
52 struct naStr* a = s1.ref.ptr.str;
53 struct naStr* b = s2.ref.ptr.str;
54 if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
55 setlen(dst, a->len + b->len);
56 memcpy(dst->data, a->data, a->len);
57 memcpy(dst->data + a->len, b->data, b->len);
61 naRef naStr_substr(naRef dest, naRef str, int start, int len)
63 struct naStr* dst = dest.ref.ptr.str;
64 struct naStr* s = str.ref.ptr.str;
65 if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
66 if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
68 memcpy(dst->data, s->data + start, len);
72 int naStr_equal(naRef s1, naRef s2)
74 struct naStr* a = s1.ref.ptr.str;
75 struct naStr* b = s2.ref.ptr.str;
76 if(a->data == b->data) return 1;
77 if(a->len != b->len) return 0;
78 if(memcmp(a->data, b->data, a->len) == 0) return 1;
82 naRef naStr_fromnum(naRef dest, double num)
84 struct naStr* dst = dest.ref.ptr.str;
85 unsigned char buf[DIGITS+8];
86 setlen(dst, fromnum(num, buf));
87 memcpy(dst->data, buf, dst->len);
91 int naStr_parsenum(char* str, int len, double* result)
93 return tonum((unsigned char*)str, len, result);
96 int naStr_tonum(naRef str, double* out)
98 return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, out);
101 int naStr_numeric(naRef str)
104 return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, &dummy);
107 void naStr_gcclean(struct naStr* str)
114 ////////////////////////////////////////////////////////////////////////
115 // Below is a custom double<->string conversion library. Why not
116 // simply use sprintf and atof? Because they aren't acceptably
117 // platform independant, sadly. I've seen some very strange results.
118 // This works the same way everywhere, although it is tied to an
119 // assumption of standard IEEE 64 bit floating point doubles.
121 // In practice, these routines work quite well. Testing conversions
122 // of random doubles to strings and back, this routine is beaten by
123 // glibc on roundoff error 23% of the time, beats glibc in 10% of
124 // cases, and ties (usually with an error of exactly zero) the
126 ////////////////////////////////////////////////////////////////////////
128 // Reads an unsigned decimal out of the scalar starting at i, stores
129 // it in v, and returns the next index to start at. Zero-length
130 // decimal numbers are allowed, and are returned as zero.
131 static int readdec(unsigned char* s, int len, int i, double* v)
134 if(i >= len) return len;
135 while(i < len && s[i] >= '0' && s[i] <= '9') {
136 *v= (*v) * 10 + (s[i] - '0');
142 // Reads a signed integer out of the string starting at i, stores it
143 // in v, and returns the next index to start at. Zero-length
144 // decimal numbers are allowed, and are returned as zero.
145 static int readsigned(unsigned char* s, int len, int i, double* v)
149 if(i >= len) { *v = 0; return len; }
150 if(s[i] == '+') { i++; }
151 else if(s[i] == '-') { i++; sgn = -1; }
152 i2 = readdec(s, len, i, &val);
153 if(i0 == i && i2 == i) {
155 return i0; // don't successfully parse bare "+" or "-"
162 // Integer decimal power utility, with a tweak that enforces
163 // integer-exactness for arguments where that is possible.
164 static double decpow(int exp)
168 if(exp < 0 || exp >= DIGITS)
171 absexp = exp < 0 ? -exp : exp;
172 while(absexp--) v *= 10.0;
176 static int tonum(unsigned char* s, int len, double* result)
179 double sgn=1, val, frac=0, exp=0;
181 // Special case, "." is not a number, even though "1." and ".0" are.
182 if(len == 1 && s[0] == '.')
185 // Strip off the leading negative sign first, so we can correctly
186 // parse things like -.xxx which would otherwise confuse
188 if(len > 1 && s[0] == '-' && s[1] != '-') {
189 sgn = -1; s++; len--;
192 // Read the integer part
193 i = readsigned(s, len, i, &val);
194 if(val < 0) { sgn = -1; val = -val; }
196 // Read the fractional part, if any
197 if(i < len && s[i] == '.') {
199 fraclen = readdec(s, len, i, &frac) - i;
203 // Nothing so far? Then the parse failed.
206 // Read the exponent, if any
207 if(i < len && (s[i] == 'e' || s[i] == 'E')) {
209 i = readsigned(s, len, i+1, &exp);
210 if(i == i0) return 0; // Must have a number after the "e"
213 // compute the result
214 *result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
216 // if we didn't use the whole string, return failure
217 if(i < len) return 0;
221 // Very simple positive (!) integer print routine. Puts the result in
222 // s and returns the number of characters written. Does not null
223 // terminate the result. Presumes at least a 32 bit integer, and
224 // cannot print integers larger than 9999999999.
225 static int decprint(int val, unsigned char* s)
228 if(val == 0) { *s = '0'; return 1; }
229 while(p <= 999999999 && p*10 <= val) p *= 10;
232 while(val >= p) { val -= p; count++; }
233 s[i++] = '0' + count;
239 // Takes a positive (!) floating point numbers, and returns exactly
240 // DIGITS decimal numbers in the buffer pointed to by s, and an
241 // integer exponent as the return value. For example, printing 1.0
242 // will result in "1000000000000000" in the buffer and -15 as the
243 // exponent. The caller can then place the floating point as needed.
244 static int rawprint(double val, unsigned char* s)
246 int exponent = (int)floor(log10(val));
247 double mantissa = val / pow(10, exponent);
249 for(i=0; i<DIGITS-1; i++) {
250 int digit = (int)floor(mantissa);
255 // Round (i.e. don't floor) the last digit
256 c = (int)floor(mantissa);
257 if(mantissa - c >= 0.5) c++;
261 return exponent - DIGITS + 1;
264 static int fromnum(double val, unsigned char* s)
266 unsigned char raw[DIGITS];
267 unsigned char* ptr = s;
271 if(val < 0) { *ptr++ = '-'; val = -val; }
273 // Exactly an integer is a special case
274 if(val == (int)val) {
275 ptr += decprint(val, ptr);
280 // Get the raw digits
281 exp = rawprint(val, raw);
283 // Examine trailing zeros to get a significant digit count
284 for(i=DIGITS-1; i>0; i--)
285 if(raw[i] != '0') break;
288 if(exp > 0 || exp < -(DIGITS+3)) {
289 // Standard scientific notation
294 for(i=1; i<digs; i++) *ptr++ = raw[i];
297 if(exp < 0) { exp = -exp; *ptr++ = '-'; }
298 else { *ptr++ = '+'; }
299 if(exp < 10) *ptr++ = '0';
300 ptr += decprint(exp, ptr);
301 } else if(exp < 1-DIGITS) {
302 // Fraction with insignificant leading zeros
303 *ptr++ = '0'; *ptr++ = '.';
304 for(i=0; i<-(exp+DIGITS); i++) *ptr++ = '0';
305 for(i=0; i<digs; i++) *ptr++ = raw[i];
308 for(i=0; i<DIGITS+exp; i++) *ptr++ = raw[i];
312 while(i<digs) *ptr++ = raw[i++];