aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/decimal.c64
-rw-r--r--src/decimal.h8
-rw-r--r--src/node.c51
3 files changed, 72 insertions, 51 deletions
diff --git a/src/decimal.c b/src/decimal.c
index 7f78c8a7..6c0bad59 100644
--- a/src/decimal.c
+++ b/src/decimal.c
@@ -1,5 +1,5 @@
/*
- Copyright 2019 David Robillard <http://drobilla.net>
+ Copyright 2019-2020 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -18,8 +18,70 @@
#include "int_math.h"
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+
int
serd_count_digits(const uint64_t i)
{
return i == 0 ? 1 : (int)serd_ilog10(i) + 1;
}
+
+unsigned
+serd_double_int_digits(const double abs)
+{
+ const double lg = ceil(log10(floor(abs) + 1.0));
+ return lg < 1.0 ? 1U : (unsigned)lg;
+}
+
+unsigned
+serd_decimals(const double d, char* const buf, const unsigned frac_digits)
+{
+ assert(isfinite(d));
+
+ // Point s to decimal point location
+ const double abs_d = fabs(d);
+ const double int_part = floor(abs_d);
+ const unsigned int_digits = serd_double_int_digits(abs_d);
+ unsigned n_bytes = 0;
+ char* s = buf + int_digits;
+ if (d < 0.0) {
+ *buf = '-';
+ ++s;
+ }
+
+ // Write integer part (right to left)
+ char* t = s - 1;
+ uint64_t dec = (uint64_t)int_part;
+ do {
+ *t-- = (char)('0' + dec % 10);
+ } while ((dec /= 10) > 0);
+
+
+ *s++ = '.';
+
+ // Write fractional part (right to left)
+ double frac_part = fabs(d - int_part);
+ if (frac_part < DBL_EPSILON) {
+ *s++ = '0';
+ n_bytes = (unsigned)(s - buf);
+ } else {
+ uint64_t frac = (uint64_t)llround(frac_part * pow(10.0, (int)frac_digits));
+ s += frac_digits - 1;
+ unsigned i = 0;
+
+ // Skip trailing zeros
+ for (; i < frac_digits - 1 && !(frac % 10); ++i, --s, frac /= 10) {}
+
+ n_bytes = (unsigned)(s - buf) + 1u;
+
+ // Write digits from last trailing zero to decimal point
+ for (; i < frac_digits; ++i) {
+ *s-- = (char)('0' + (frac % 10));
+ frac /= 10;
+ }
+ }
+
+ return n_bytes;
+}
diff --git a/src/decimal.h b/src/decimal.h
index 11e6a9bf..eefc07ef 100644
--- a/src/decimal.h
+++ b/src/decimal.h
@@ -1,5 +1,5 @@
/*
- Copyright 2019 David Robillard <http://drobilla.net>
+ Copyright 2019-2020 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -23,4 +23,10 @@
int
serd_count_digits(uint64_t i);
+unsigned
+serd_double_int_digits(double abs);
+
+unsigned
+serd_decimals(double d, char* buf, unsigned frac_digits);
+
#endif // SERD_DECIMAL_H
diff --git a/src/node.c b/src/node.c
index b362aaa8..34dada0b 100644
--- a/src/node.c
+++ b/src/node.c
@@ -25,7 +25,6 @@
#include "serd/serd.h"
#include <assert.h>
-#include <float.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
@@ -566,13 +565,6 @@ serd_new_relative_uri(const char* str,
return node;
}
-static inline unsigned
-serd_digits(double abs)
-{
- const double lg = ceil(log10(floor(abs) + 1.0));
- return lg < 1.0 ? 1U : (unsigned)lg;
-}
-
SerdNode*
serd_new_decimal(double d, unsigned frac_digits, const SerdNode* datatype)
{
@@ -582,7 +574,7 @@ serd_new_decimal(double d, unsigned frac_digits, const SerdNode* datatype)
const SerdNode* type = datatype ? datatype : &serd_xsd_decimal.node;
const double abs_d = fabs(d);
- const unsigned int_digits = serd_digits(abs_d);
+ const unsigned int_digits = serd_double_int_digits(abs_d);
const size_t len = int_digits + frac_digits + 3;
const size_t type_len = serd_node_total_size(type);
const size_t total_len = len + type_len;
@@ -590,46 +582,7 @@ serd_new_decimal(double d, unsigned frac_digits, const SerdNode* datatype)
SerdNode* const node =
serd_node_malloc(total_len, SERD_HAS_DATATYPE, SERD_LITERAL);
- // Point s to decimal point location
- char* const buf = serd_node_buffer(node);
- const double int_part = floor(abs_d);
- char* s = buf + int_digits;
- if (d < 0.0) {
- *buf = '-';
- ++s;
- }
-
- // Write integer part (right to left)
- char* t = s - 1;
- uint64_t dec = (uint64_t)int_part;
- do {
- *t-- = (char)('0' + dec % 10);
- } while ((dec /= 10) > 0);
-
-
- *s++ = '.';
-
- // Write fractional part (right to left)
- double frac_part = fabs(d - int_part);
- if (frac_part < DBL_EPSILON) {
- *s++ = '0';
- node->n_bytes = (size_t)(s - buf);
- } else {
- uint64_t frac = (uint64_t)llround(frac_part * pow(10.0, (int)frac_digits));
- s += frac_digits - 1;
- unsigned i = 0;
-
- // Skip trailing zeros
- for (; i < frac_digits - 1 && !(frac % 10); ++i, --s, frac /= 10) {}
-
- node->n_bytes = (size_t)(s - buf) + 1u;
-
- // Write digits from last trailing zero to decimal point
- for (; i < frac_digits; ++i) {
- *s-- = (char)('0' + (frac % 10));
- frac /= 10;
- }
- }
+ node->n_bytes = serd_decimals(d, serd_node_buffer(node), frac_digits);
memcpy(serd_node_meta(node), type, type_len);
serd_node_check_padding(node);