aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/String/Core.c2
-rw-r--r--src/String/Float.c420
-rw-r--r--src/String/Int.c14
-rw-r--r--test/src/TestFloat.c (renamed from test/src/TestString.c)99
4 files changed, 434 insertions, 101 deletions
diff --git a/src/String/Core.c b/src/String/Core.c
index 4dfef4b..85bc7d1 100644
--- a/src/String/Core.c
+++ b/src/String/Core.c
@@ -12,7 +12,7 @@ void BH_StringFree(char *string)
char *BH_StringCopy(const char *string)
{
char *result;
-
+
result = malloc(strlen(string) + 1);
if (result)
strcpy(result, string);
diff --git a/src/String/Float.c b/src/String/Float.c
index cb05017..f1e39c4 100644
--- a/src/String/Float.c
+++ b/src/String/Float.c
@@ -4,14 +4,17 @@
#include <ctype.h>
#include <float.h>
#include <math.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
+/* Common defines */
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define BUFSIZE 309
-#define DIGITS 70
+#define DIGITS 80
+
+/* Modes */
#define NORMAL 0
#define ABSOLUTE 1
#define RELATIVE 2
@@ -30,13 +33,13 @@ struct DragonState
BInt mm;
BInt mp;
BInt tmp[5];
+ long k;
int cutoff;
- int k;
};
static const BInt BInt1 = {1, {1}};
-static const BInt BInt10 = {1, {10}};
+static const BInt BInt53 = {4, {0x0000, 0x0000, 0x0000, 0x0020}};
static const uint8_t clzLookup[256] =
@@ -60,6 +63,30 @@ static const uint8_t clzLookup[256] =
};
+static const BInt powLookup[] =
+{
+ {1, {0x000A}},
+ {1, {0x0064}},
+ {1, {0x2710}},
+ {2, {0xE100, 0x05F5}},
+ {4, {0x0000, 0x6FC1, 0x86F2, 0x0023}},
+ {7, {0x0000, 0x0000, 0xEF81, 0x85AC, 0x415B, 0x2D6D, 0x04EE}},
+ {14, {0x0000, 0x0000, 0x0000, 0x0000, 0x1F01, 0xBF6A, 0xED64, 0x6E38,
+ 0x97ED, 0xDAA7, 0xF9F4, 0xE93F, 0x4F03, 0x0018}},
+ {27, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3E01, 0x2E95, 0x9909, 0x03DF, 0x38FD, 0x0F15, 0xE42F, 0x2374,
+ 0xF5EC, 0xD3CF, 0xDC08, 0xC404, 0xB0DA, 0xBCCD, 0x7F19, 0xA633,
+ 0x2603, 0xE91F, 0x024E}},
+ {54, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x7C01, 0x982E, 0x875B, 0xBED3, 0x9F72, 0xD8D9, 0x2F87, 0x1215,
+ 0x50C6, 0x6BDE, 0x6E70, 0xCF4A, 0xD80F, 0xD595, 0x716E, 0x26B2,
+ 0x66B0, 0xADC6, 0x3624, 0x1D15, 0xD35A, 0x3C42, 0x540E, 0x63FF,
+ 0x73C0, 0xCC55, 0xEF17, 0x65F9, 0x28F2, 0x55BC, 0xC7F7, 0x80DC,
+ 0xEDDC, 0xF46E, 0xEFCE, 0x5FDC, 0x53F7, 0x0005}}
+};
+
+
static int BIntClz(uint16_t value)
{
if (value & 0xFF00)
@@ -69,8 +96,22 @@ static int BIntClz(uint16_t value)
}
+static int BIntLog2(const BInt *in)
+{
+ /* Preconditions */
+ assert(in != NULL);
+ assert(in->size != 0);
+ assert(in->data[in->size - 1] != 0);
+
+ return 15 - BIntClz(in->data[in->size - 1]) + 16 * (in->size - 1);
+}
+
+
static void BIntTrim(BInt *in)
{
+ /* Preconditions */
+ assert(in != NULL);
+
while (in->size && !in->data[in->size - 1])
in->size--;
}
@@ -81,6 +122,9 @@ static int BIntCompare(const BInt *a,
{
int i;
+ /* Preconditions */
+ assert(a != NULL && b != NULL);
+
/* Compare by lengths */
i = a->size - b->size;
if (a->size - b->size)
@@ -106,6 +150,8 @@ static void BIntAdd(const BInt *a,
uint32_t carry;
int i;
+ /* Preconditions */
+ assert(a != NULL && b != NULL && out != NULL);
assert(a->size + 1 <= DIGITS);
assert(b->size + 1 <= DIGITS);
@@ -117,7 +163,7 @@ static void BIntAdd(const BInt *a,
carry += a->data[i];
if (i < b->size)
carry += b->data[i];
-
+
out->data[i] = carry & 0xFFFF;
carry = (carry >> 16);
}
@@ -137,6 +183,10 @@ static void BIntSub(const BInt *a,
uint32_t carry;
int i;
+ /* Preconditions */
+ assert(a != NULL && b != NULL && out != NULL);
+ assert(BIntCompare(a, b) >= 0);
+
/* Main subtraction loop */
carry = 0;
for (i = 0; i < a->size || i < b->size; i++)
@@ -145,7 +195,7 @@ static void BIntSub(const BInt *a,
carry += a->data[i];
if (i < b->size)
carry -= b->data[i];
-
+
out->data[i] = carry & 0xFFFF;
carry = (carry & 0xFFFF0000) | (carry >> 16);
}
@@ -163,6 +213,8 @@ static void BIntMul(const BInt *a,
uint32_t carry;
int i, j;
+ /* Preconditions */
+ assert(a != NULL && b != NULL && out != NULL);
assert(a->size + b->size <= DIGITS);
/* Zero out the result */
@@ -197,6 +249,8 @@ static void BIntMulDigit(const BInt *a,
uint32_t carry;
int i;
+ /* Preconditions */
+ assert(a != NULL && out != NULL);
assert(a->size + 1 <= DIGITS);
/* Multiplication loop */
@@ -215,6 +269,30 @@ static void BIntMulDigit(const BInt *a,
}
+static void BIntPow10(const BInt *in,
+ int exponent,
+ BInt *out,
+ BInt *tmp)
+{
+ int i, current;
+
+ /* Preconditions */
+ assert(in != NULL && out != NULL && tmp != NULL);
+ assert(exponent >= 0 && exponent < 512);
+
+ tmp[0] = *in;
+ for (current = 0, i = 0; exponent; i++, exponent >>= 1)
+ {
+ if (!(exponent & 0x1))
+ continue;
+
+ BIntMul(&tmp[current], &powLookup[i], &tmp[1 - current]);
+ current = 1 - current;
+ }
+ *out = tmp[current];
+}
+
+
static void BIntLsh(const BInt *in,
int amount,
BInt *out)
@@ -222,11 +300,12 @@ static void BIntLsh(const BInt *in,
int blocks, bits, i;
uint16_t low, high;
+ /* Preconditions */
+ assert(in != NULL && out != NULL);
+ assert(amount >= 0 && in->size + (amount + 15) / 16 <= DIGITS);
+
blocks = amount / 16;
bits = amount % 16;
-
- assert(in->size + blocks + (bits > 0) <= DIGITS);
-
if (!in->size)
{
out->size = 0;
@@ -245,14 +324,14 @@ static void BIntLsh(const BInt *in,
}
out->data[i] = high;
out->size = in->size + blocks + 1;
- }
+ }
else
{
for (i = in->size; i; i--)
out->data[i - 1 + blocks] = in->data[i - 1];
out->size = in->size + blocks;
}
-
+
/* Trim leading zeros and zero out lower blocks */
BIntTrim(out);
for (i = blocks; i; i--)
@@ -267,6 +346,10 @@ static void BIntRsh(const BInt *in,
int blocks, bits, i;
uint16_t low, high;
+ /* Preconditions */
+ assert(in != NULL && out != NULL);
+ assert(amount >= 0);
+
blocks = amount / 16;
bits = amount % 16;
@@ -299,6 +382,10 @@ static uint16_t BIntGuess(const BInt *a,
{
uint32_t tmp;
+ /* Preconditions */
+ assert(a != NULL && b != NULL);
+ assert(a->size > 0 && b->size > 0);
+
if (BIntCompare(a, b) < 0)
return 0;
@@ -319,6 +406,10 @@ static void BIntDiv(const BInt *a,
uint16_t digit;
int shift;
+ /* Preconditions */
+ assert(a != NULL && b != NULL && q != NULL && r != NULL && tmp != NULL);
+ assert(b->size != 0);
+
/* Handle case where a is less then b */
if (BIntCompare(a, b) < 0)
{
@@ -331,7 +422,7 @@ static void BIntDiv(const BInt *a,
shift = BIntClz(b->data[b->size - 1]);
BIntLsh(a, shift, &tmp[0]);
BIntLsh(b, shift, &tmp[1]);
-
+
/* Prepare first step of the division */
q->size = 0;
r->size = 0;
@@ -377,8 +468,15 @@ static void BIntDiv(const BInt *a,
static void dragonFixup(struct DragonState *state,
int precision,
int mode,
- uint64_t f)
+ uint64_t f,
+ int exp)
{
+ /* Preconditions */
+ assert(state != NULL);
+ assert(mode == NORMAL || mode == ABSOLUTE || mode == RELATIVE);
+ assert(precision >= 0);
+
+ /* Account for unqual gaps */
if (f == (((uint64_t)1) << 52))
{
BIntLsh(&state->mp, 1, &state->mp);
@@ -387,31 +485,37 @@ static void dragonFixup(struct DragonState *state,
}
state->k = 0;
- BIntDiv(&state->s, &BInt10, &state->tmp[0], &state->tmp[1], state->tmp + 2);
- if (state->tmp[1].size)
- BIntAdd(&state->tmp[0], &BInt1, &state->tmp[0]);
+ /* Burger/Dybvig approach */
+ state->k = BIntClz((f >> 48) & 0xFFFF);
+ state->k += (state->k == 16) ? (BIntClz((f >> 32) & 0xFFFF)) : (0);
+ state->k += (state->k == 32) ? (BIntClz((f >> 16) & 0xFFFF)) : (0);
+ state->k += (state->k == 48) ? (BIntClz(f & 0xFFFF)) : (0);
- while (BIntCompare(&state->r, &state->tmp[0]) < 0)
+ /* 77 / 256 is an approximation for Log(2) or 0.30102999 */
+ state->k = (63 - state->k + exp - 54) * 77;
+ if (state->k < 0)
+ state->k = (state->k / 256);
+ else
+ state->k = (state->k / 256) + ((state->k & 0xFF) > 0);
+
+ /* Scale numbers accordinaly */
+ if (state->k < 0)
{
- state->k -= 1;
- BIntMulDigit(&state->r, 10, &state->r);
- BIntMulDigit(&state->mm, 10, &state->mm);
- BIntMulDigit(&state->mp, 10, &state->mp);
- BIntDiv(&state->s, &BInt10, &state->tmp[0], &state->tmp[1], state->tmp + 2);
- if (state->tmp[1].size)
- BIntAdd(&state->tmp[0], &BInt1, &state->tmp[0]);
+ BIntPow10(&state->r, -state->k, &state->r, state->tmp);
+ BIntPow10(&state->mm, -state->k, &state->mm, state->tmp);
+ BIntPow10(&state->mp, -state->k, &state->mp, state->tmp);
}
+ else if (state->k > 0)
+ BIntPow10(&state->s, state->k, &state->s, state->tmp);
- BIntLsh(&state->r, 1, &state->tmp[0]);
- BIntAdd(&state->tmp[0], &state->mp, &state->tmp[0]);
- BIntLsh(&state->s, 1, &state->tmp[1]);
- while (BIntCompare(&state->tmp[0], &state->tmp[1]) >= 0)
+ /* Scale S if we underestimated */
+ if (BIntCompare(&state->r, &state->s) >= 0)
{
state->k += 1;
BIntMulDigit(&state->s, 10, &state->s);
- BIntLsh(&state->s, 1, &state->tmp[1]);
}
+ /* Find cutoff */
if (mode == NORMAL)
state->cutoff = state->k - BUFSIZE;
else if (mode == RELATIVE)
@@ -431,6 +535,10 @@ static void dragonRound(struct DragonState *state,
{
int i;
+ /* Preconditions */
+ assert(state != NULL && buffer != NULL && k != NULL && size != NULL);
+ assert(s >= '0' && s <= '9');
+
/* Check if rounding up required */
if (high == low)
{
@@ -446,7 +554,7 @@ static void dragonRound(struct DragonState *state,
{
for (i = *size; i && buffer[i - 1] == '9'; i--)
buffer[i - 1] = '0';
-
+
if (i > 0)
buffer[i - 1]++;
else
@@ -458,7 +566,7 @@ static void dragonRound(struct DragonState *state,
}
-static void dragon(double value,
+static void dragon(double value,
int precision,
int mode,
char *buffer,
@@ -470,6 +578,11 @@ static void dragon(double value,
uint64_t f;
char s;
+ /* Preconditions */
+ assert(buffer != NULL && size != NULL && k != NULL);
+ assert(mode == NORMAL || mode == ABSOLUTE || mode == RELATIVE);
+ assert(precision >= 0);
+
*k = 0;
*size = low = high = 0;
@@ -490,16 +603,16 @@ static void dragon(double value,
BIntLsh(&BInt1, MAX(0, -(e - 53)), &state.s);
BIntLsh(&BInt1, MAX(e - 53, 0), &state.mm);
BIntLsh(&BInt1, MAX(e - 53, 0), &state.mp);
- dragonFixup(&state, precision, mode, f);
+ dragonFixup(&state, precision, mode, f, e);
/* Main digit generation loop */
*k = state.k - 1;
- while(1)
+ while(1)
{
state.k -= 1;
BIntMulDigit(&state.r, 10, &state.r);
- BIntDiv(&state.r, &state.s, &state.tmp[0], &state.r, state.tmp + 1);
-
+ BIntDiv(&state.r, &state.s, &state.tmp[0], &state.r, &state.tmp[1]);
+
s = '0';
if (state.tmp[0].size)
s += state.tmp[0].data[0];
@@ -507,13 +620,13 @@ static void dragon(double value,
if (mode == NORMAL)
{
- BIntLsh(&state.r, 1, &state.tmp[1]);
- BIntLsh(&state.s, 1, &state.tmp[2]);
- BIntSub(&state.tmp[2], &state.mp, &state.tmp[2]);
BIntMulDigit(&state.mm, 10, &state.mm);
BIntMulDigit(&state.mp, 10, &state.mp);
+ BIntLsh(&state.r, 1, &state.tmp[1]);
+ BIntLsh(&state.s, 1, &state.tmp[2]);
+ BIntAdd(&state.tmp[1], &state.mp, &state.tmp[3]);
low = BIntCompare(&state.tmp[1], &state.mm) < 0;
- high = BIntCompare(&state.tmp[1], &state.tmp[2]) > 0;
+ high = BIntCompare(&state.tmp[3], &state.tmp[2]) > 0;
if (low || high || state.k == state.cutoff || *size >= BUFSIZE)
break;
}
@@ -529,7 +642,7 @@ static void dragon(double value,
}
-static char *formatF(char buffer[BUFSIZE],
+static char *formatF(char *buffer,
int precision,
int sign,
int k,
@@ -537,7 +650,11 @@ static char *formatF(char buffer[BUFSIZE],
{
char *result, *current;
int i;
-
+
+ /* Preconditions */
+ assert(buffer != NULL);
+ assert(size < BUFSIZE);
+
result = malloc(MAX(0, k) + 5 + sign + precision);
current = result;
if (!result)
@@ -552,9 +669,9 @@ static char *formatF(char buffer[BUFSIZE],
{
*(current++) = '0';
- if (precision > 0)
+ if (precision > 0)
*(current++) = '.';
-
+
for (i = 0; i < MIN(-k - 1, precision); i++)
*(current++) = '0';
}
@@ -576,7 +693,7 @@ static char *formatF(char buffer[BUFSIZE],
}
-static char *formatE(char buffer[BUFSIZE],
+static char *formatE(char *buffer,
int precision,
int sign,
int k,
@@ -586,6 +703,12 @@ static char *formatE(char buffer[BUFSIZE],
char *result, *current;
int i;
+ /* Preconditions */
+ assert(buffer != NULL);
+ assert(size < BUFSIZE);
+ assert(sign == 0 || sign == 1);
+ assert(upper == 0 || upper == 1);
+
result = malloc(9 + sign + precision);
current = result;
if (!result)
@@ -594,7 +717,7 @@ static char *formatE(char buffer[BUFSIZE],
/* Add sign and digits */
if (sign)
*(current++) = '-';
-
+
for (i = 0; i < size; i++)
{
*(current++) = buffer[i];
@@ -605,7 +728,7 @@ static char *formatE(char buffer[BUFSIZE],
/* Pad to specified precision */
for (; i < precision + 1; i++)
*(current++) = '0';
-
+
/* Add exponent symbol and sign */
*(current++) = "eE"[upper];
if (k < 0)
@@ -717,11 +840,11 @@ char *BH_StringFromDouble(double value,
static const char *infStrings[] = { "inf", "-inf", "INF", "-INF" };
static const char *nanStrings[] = { "nan", "NAN" };
int sign, type, upper;
-
+
type = BH_ClassifyDouble(value);
upper = isupper(format) > 0;
sign = (type & BH_FP_NEGATIVE) != 0;
-
+
if (sign)
value = fabs(value);
@@ -740,45 +863,87 @@ char *BH_StringFromDouble(double value,
}
-double BH_StringToDouble(const char *string,
- size_t *size)
+static int caselessCompare(const char *src,
+ const char *ref)
+{
+ /* Preconditions */
+ assert(src != NULL && ref != NULL);
+
+ for (; *src && *ref && tolower(*src) == tolower(*ref); src++, ref++);
+
+ if (*ref == 0)
+ return 0;
+
+ return *src - *ref;
+}
+
+
+static int parseFormat(const char *string,
+ size_t *size,
+ char *buffer,
+ int *sign,
+ int *e,
+ int *type)
{
- int nsign, esign, e, dot;
const char *current;
- char buffer[4];
- size_t count;
+ int esign, dot, count;
+
+ /* Preconditions */
+ assert(string != NULL && buffer != NULL && sign != NULL && e != NULL && type != NULL);
- nsign = 0; esign = 0; e = 0; count = 0; dot = 0;
+ *sign = *e = esign = count = dot = 0;
+ *type = BH_FP_ZERO;
current = string;
-
+
/* Skip whitespace */
while (isspace(*current))
current++;
-
+
+ /* Check for NaN */
+ if (caselessCompare(current, "nan") == 0)
+ {
+ *type = BH_FP_NAN; current += 3;
+ goto done;
+ }
+
/* Leading sign */
if (*current == '+' || *current == '-')
{
if (*current == '-')
- nsign = 1;
+ *sign = 1;
current++;
}
-
+
+ /* Check for infinity */
+ if (caselessCompare(current, "infinity") == 0)
+ {
+ *type = BH_FP_INFINITE; current += 8;
+ goto done;
+ }
+ else if (caselessCompare(current, "inf") == 0)
+ {
+ *type = BH_FP_INFINITE; current += 3;
+ goto done;
+ }
+
/* Read integer part of the float */
for (; isdigit(*current); current++)
{
- if (count < sizeof(buffer) && (count || *current != '0'))
+ *type = BH_FP_NORMAL;
+ if (count < 20 && (count || *current != '0'))
buffer[count++] = *current;
- else if (count >= sizeof(buffer))
+ else if (count >= 20)
dot--;
}
/* Read fract part of the float */
if (*current == '.')
current++;
-
+
for (; isdigit(*current); current++)
{
- if ((count < sizeof(buffer)))
+ *type = BH_FP_NORMAL;
+ if ((count < 20))
{
dot++;
if ((count || *current != '0'))
@@ -798,17 +963,134 @@ double BH_StringToDouble(const char *string,
}
for (; isdigit(*current); current++)
- e = e * 10 + *current - '0';
+ *e = *e * 10 + *current - '0';
}
if (esign)
- e = -e;
- e -= dot;
+ *e = -*e;
+ *e -= dot;
+done:
if (size)
*size = current - string;
-
- BH_UNUSED(nsign);
- BH_UNUSED(BIntMul);
- return 0.0;
+
+ return count;
+}
+
+
+double BH_StringToDouble(const char *string,
+ size_t *size)
+{
+ int type, e, sign, i, count, shift;
+ BInt r, s, tmp[5];
+ char buffer[20];
+ double result;
+ uint64_t f;
+
+ /* Preconditions */
+ assert(string != NULL);
+
+ /* Parse from string format */
+ count = parseFormat(string, size, buffer, &sign, &e, &type);
+
+ /* Handle special values */
+ if (type == BH_FP_INFINITE)
+ {
+ if (sign)
+ return -INFINITY;
+ return INFINITY;
+ }
+ else if (type == BH_FP_NAN)
+ return NAN;
+ else if (type == BH_FP_ZERO)
+ {
+ /* Hacky solution to indicate we haven't seen any digit */
+ if (size)
+ *size = 0;
+ return 0.0;
+ }
+
+ /* Handle zero input */
+ if (count == 0)
+ {
+ if (sign)
+ return -0.0;
+ return 0.0;
+ }
+
+ /* Exponent too low */
+ if (e < -329)
+ {
+ if (sign)
+ return -0.0;
+ return 0.0;
+ }
+
+ /* Exponent too high */
+ if (e > 292)
+ {
+ if (sign)
+ return -INFINITY;
+ return INFINITY;
+ }
+
+ /* Convert character buffer into integers */
+ tmp[0].size = 1;
+ r.size = 0;
+ s = BInt1;
+ for (i = 0; i < count; i++)
+ {
+ tmp[0].data[0] = buffer[i] - '0';
+ BIntMulDigit(&r, 10, &r);
+ BIntAdd(&r, &tmp[0], &r);
+ }
+
+ if (e >= 0)
+ BIntPow10(&r, e, &r, &tmp[0]);
+ else
+ BIntPow10(&s, -e, &s, &tmp[0]);
+
+ /* Calculate required shift */
+ shift = -52;
+ if (BIntCompare(&r, &s) >= 0)
+ {
+ BIntDiv(&r, &s, &tmp[0], &tmp[1], &tmp[2]);
+ shift += BIntLog2(&tmp[0]);
+ }
+ else
+ {
+ BIntDiv(&s, &r, &tmp[0], &tmp[1], &tmp[2]);
+ shift += -(BIntLog2(&tmp[0]) + 1);
+ }
+
+ /* Shift */
+ if (shift > 0)
+ BIntLsh(&s, shift, &s);
+ else if (shift < 0)
+ BIntLsh(&r, -shift, &r);
+
+ /* Calculate final exponent and 53 bit integer */
+ BIntDiv(&r, &s, &tmp[0], &tmp[1], &tmp[2]);
+ BIntRsh(&s, 1, &s);
+ if (BIntCompare(&tmp[1], &s) > 0 || (BIntCompare(&tmp[1], &s) == 0 && (tmp[0].data[0] & 0x1)))
+ {
+ BIntAdd(&tmp[0], &BInt1, &tmp[0]);
+ if (BIntCompare(&tmp[0], &BInt53) >= 0)
+ {
+ BIntRsh(&tmp[0], 1, &tmp[0]);
+ shift++;
+ }
+ }
+
+ /* Create double from integer and exponent */
+ f = (tmp[0].data[3] & 0x1F);
+ f = (f << 16) | tmp[0].data[2];
+ f = (f << 16) | tmp[0].data[1];
+ f = (f << 16) | tmp[0].data[0];
+
+ result = ldexp(f, shift);
+ if (sign)
+ result = -result;
+
+ return result;
}
diff --git a/src/String/Int.c b/src/String/Int.c
index 90379d9..a9edf90 100644
--- a/src/String/Int.c
+++ b/src/String/Int.c
@@ -47,30 +47,30 @@ static void guessBase(const char **string,
size_t *size,
int *base)
{
- if (*base != 0)
+ if (*base != 0)
return;
*base = 10;
- if (**string != '0')
+ if (**string != '0')
return;
(*string)++;
- if (size)
+ if (size)
(*size)++;
switch (**string)
{
case 'x': case 'X':
- *base = 16;
+ *base = 16;
(*string)++;
- if (size)
+ if (size)
(*size)++;
break;
case 'b': case 'B':
- *base = 2;
+ *base = 2;
(*string)++;
- if (size)
+ if (size)
(*size)++;
break;
diff --git a/test/src/TestString.c b/test/src/TestFloat.c
index 53811cf..dac6171 100644
--- a/test/src/TestString.c
+++ b/test/src/TestFloat.c
@@ -1,6 +1,8 @@
#include <BH/String.h>
+#include <BH/Util.h>
#include <BH/Unit.h>
#include <float.h>
+#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -18,7 +20,7 @@ static int compareString(double value,
result = strcmp(str, ref);
if (result)
printf("Value: %.17g\tReference: %s\tGot: %s\n", value, ref, str);
-
+
BH_StringFree(str);
return result;
@@ -32,10 +34,10 @@ static int roundtripString(double value,
char *str;
str = BH_StringFromDouble(value, format, -1);
- result = strtod(str, NULL);
+ result = BH_StringToDouble(str, NULL);
if (result != value)
printf("Value: %.17g\tGot: %.17g\tStr: %s\n", value, result, str);
-
+
BH_StringFree(str);
return result != value;
@@ -94,10 +96,6 @@ BH_UNIT_TEST(FixedRoundTrip)
{
BH_VERIFY(roundtripString(1.0, 'f') == 0);
BH_VERIFY(roundtripString(-1.0, 'f') == 0);
- BH_VERIFY(roundtripString(DBL_MIN, 'f') == 0);
- BH_VERIFY(roundtripString(-DBL_MIN, 'f') == 0);
- BH_VERIFY(roundtripString(DBL_MAX, 'f') == 0);
- BH_VERIFY(roundtripString(-DBL_MAX, 'f') == 0);
BH_VERIFY(roundtripString(0.0, 'f') == 0);
BH_VERIFY(roundtripString(-0.0, 'f') == 0);
BH_VERIFY(roundtripString(3.14159, 'f') == 0);
@@ -108,8 +106,12 @@ BH_UNIT_TEST(FixedRoundTrip)
BH_VERIFY(roundtripString(-0.81, 'f') == 0);
BH_VERIFY(roundtripString(0.81, 'f') == 0);
BH_VERIFY(roundtripString(-0.81, 'f') == 0);
- BH_VERIFY(roundtripString(144115188075855877, 'f') == 0);
- BH_VERIFY(roundtripString(-144115188075855877, 'f') == 0);
+ BH_VERIFY(roundtripString(144115188075855877.0, 'f') == 0);
+ BH_VERIFY(roundtripString(-144115188075855877.0, 'f') == 0);
+ BH_VERIFY(roundtripString(DBL_MIN, 'f') == 0);
+ BH_VERIFY(roundtripString(-DBL_MIN, 'f') == 0);
+ BH_VERIFY(roundtripString(DBL_MAX, 'f') == 0);
+ BH_VERIFY(roundtripString(-DBL_MAX, 'f') == 0);
return 0;
}
@@ -206,8 +208,8 @@ BH_UNIT_TEST(ShortestFormat)
BH_VERIFY(compareString(-1230000000.00123, 'g', 1, "-1e+09") == 0);
BH_VERIFY(compareString(-1230000000.00123, 'g', 2, "-1.2e+09") == 0);
BH_VERIFY(compareString(-1230000000.00123, 'g', 3, "-1.23e+09") == 0);
- BH_VERIFY(compareString(144115188075855877, 'g', 17, "1.4411518807585587e+17") == 0);
- BH_VERIFY(compareString(-144115188075855877, 'g', 17, "-1.4411518807585587e+17") == 0);
+ BH_VERIFY(compareString(144115188075855877.0, 'g', 17, "1.4411518807585587e+17") == 0);
+ BH_VERIFY(compareString(-144115188075855877.0, 'g', 17, "-1.4411518807585587e+17") == 0);
return 0;
}
@@ -217,10 +219,6 @@ BH_UNIT_TEST(ScientificRoundTrip)
{
BH_VERIFY(roundtripString(1.0, 'e') == 0);
BH_VERIFY(roundtripString(-1.0, 'e') == 0);
- BH_VERIFY(roundtripString(DBL_MIN, 'e') == 0);
- BH_VERIFY(roundtripString(-DBL_MIN, 'e') == 0);
- BH_VERIFY(roundtripString(DBL_MAX, 'e') == 0);
- BH_VERIFY(roundtripString(-DBL_MAX, 'e') == 0);
BH_VERIFY(roundtripString(0.0, 'e') == 0);
BH_VERIFY(roundtripString(-0.0, 'e') == 0);
BH_VERIFY(roundtripString(3.14159, 'e') == 0);
@@ -231,8 +229,12 @@ BH_UNIT_TEST(ScientificRoundTrip)
BH_VERIFY(roundtripString(-0.81, 'e') == 0);
BH_VERIFY(roundtripString(0.81, 'e') == 0);
BH_VERIFY(roundtripString(-0.81, 'e') == 0);
- BH_VERIFY(roundtripString(144115188075855877, 'e') == 0);
- BH_VERIFY(roundtripString(-144115188075855877, 'e') == 0);
+ BH_VERIFY(roundtripString(144115188075855877.0, 'e') == 0);
+ BH_VERIFY(roundtripString(-144115188075855877.0, 'e') == 0);
+ BH_VERIFY(roundtripString(DBL_MIN, 'e') == 0);
+ BH_VERIFY(roundtripString(-DBL_MIN, 'e') == 0);
+ BH_VERIFY(roundtripString(DBL_MAX, 'e') == 0);
+ BH_VERIFY(roundtripString(-DBL_MAX, 'e') == 0);
return 0;
}
@@ -242,10 +244,6 @@ BH_UNIT_TEST(ShortestRoundTrip)
{
BH_VERIFY(roundtripString(1.0, 'g') == 0);
BH_VERIFY(roundtripString(-1.0, 'g') == 0);
- BH_VERIFY(roundtripString(DBL_MIN, 'g') == 0);
- BH_VERIFY(roundtripString(-DBL_MIN, 'g') == 0);
- BH_VERIFY(roundtripString(DBL_MAX, 'g') == 0);
- BH_VERIFY(roundtripString(-DBL_MAX, 'g') == 0);
BH_VERIFY(roundtripString(0.0, 'g') == 0);
BH_VERIFY(roundtripString(-0.0, 'g') == 0);
BH_VERIFY(roundtripString(3.14159, 'g') == 0);
@@ -256,8 +254,12 @@ BH_UNIT_TEST(ShortestRoundTrip)
BH_VERIFY(roundtripString(-0.81, 'g') == 0);
BH_VERIFY(roundtripString(0.81, 'g') == 0);
BH_VERIFY(roundtripString(-0.81, 'g') == 0);
- BH_VERIFY(roundtripString(144115188075855877, 'g') == 0);
- BH_VERIFY(roundtripString(-144115188075855877, 'g') == 0);
+ BH_VERIFY(roundtripString(144115188075855877.0, 'g') == 0);
+ BH_VERIFY(roundtripString(-144115188075855877.0, 'g') == 0);
+ BH_VERIFY(roundtripString(DBL_MIN, 'g') == 0);
+ BH_VERIFY(roundtripString(-DBL_MIN, 'g') == 0);
+ BH_VERIFY(roundtripString(DBL_MAX, 'g') == 0);
+ BH_VERIFY(roundtripString(-DBL_MAX, 'g') == 0);
return 0;
}
@@ -292,7 +294,7 @@ BH_UNIT_TEST(Parity)
if (strcmp(str, output))
{
printf("(%.17g) (%d) %s vs %s\n", value, k, str, output);
- BH_FAIL("Not equal");
+ BH_FAIL("Strings aren't equal");
}
BH_StringFree(str);
}
@@ -303,6 +305,54 @@ BH_UNIT_TEST(Parity)
}
+BH_UNIT_TEST(ToDouble)
+{
+ size_t size;
+
+ BH_VERIFY(BH_ClassifyDouble(BH_StringToDouble(" INFa ", &size)) == BH_FP_INFINITE);
+ BH_VERIFY(size == 5);
+ BH_VERIFY(BH_ClassifyDouble(BH_StringToDouble(" INFINITYc ", &size)) == BH_FP_INFINITE);
+ BH_VERIFY(size == 10);
+
+ BH_VERIFY(BH_ClassifyDouble(BH_StringToDouble(" -INFb ", &size)) == (BH_FP_INFINITE | BH_FP_NEGATIVE));
+ BH_VERIFY(size == 6);
+ BH_VERIFY(BH_ClassifyDouble(BH_StringToDouble(" -INFINITYd ", &size)) == (BH_FP_INFINITE | BH_FP_NEGATIVE));
+ BH_VERIFY(size == 11);
+
+ BH_VERIFY(BH_ClassifyDouble(BH_StringToDouble(" NANe ", &size)) == BH_FP_NAN);
+ BH_VERIFY(size == 5);
+
+ BH_VERIFY_DELTA(BH_StringToDouble(" 1234.0312f ", &size), 1234.0312, 0.00001);
+ BH_VERIFY(size == 11);
+
+ BH_VERIFY_DELTA(BH_StringToDouble(" 3.14159g ", &size), 3.14159, 0.00001);
+ BH_VERIFY(size == 9);
+
+ BH_VERIFY(BH_StringToDouble(" h ", &size) == 0.0);
+ BH_VERIFY(size == 0);
+
+ BH_VERIFY(BH_StringToDouble(" 0 ", &size) == 0.0);
+ BH_VERIFY(size == 3);
+
+ BH_VERIFY(BH_StringToDouble(" 0.0 ", &size) == 0.0);
+ BH_VERIFY(size == 5);
+
+ BH_VERIFY(BH_StringToDouble(" 0. ", &size) == 0.0);
+ BH_VERIFY(size == 4);
+
+ BH_VERIFY(BH_StringToDouble(" .0 ", &size) == 0.0);
+ BH_VERIFY(size == 4);
+
+ BH_VERIFY(BH_StringToDouble(" .Hello ", &size) == 0.0);
+ BH_VERIFY(size == 0);
+
+ BH_VERIFY(BH_StringToDouble(" .E12 ", &size) == 0.0);
+ BH_VERIFY(size == 0);
+
+ return 0;
+}
+
+
int main(int argc, char **argv)
{
BH_UNUSED(argc);
@@ -315,6 +365,7 @@ int main(int argc, char **argv)
BH_UNIT_ADD(ShortestFormat);
BH_UNIT_ADD(ShortestRoundTrip);
BH_UNIT_ADD(Parity);
+ BH_UNIT_ADD(ToDouble);
return BH_UnitRun();
}