Change in libosmocore[master]: add osmo_float_str_to_int() and osmo_int_to_float_str_*()

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Thu Oct 8 07:00:38 UTC 2020


laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmocore/+/20331 )

Change subject: add osmo_float_str_to_int() and osmo_int_to_float_str_*()
......................................................................

add osmo_float_str_to_int() and osmo_int_to_float_str_*()

This will be useful to handle latitude and longitude numbers for GAD, which is
the location estimate representation used for LCS (Location Services).

The OsmoSMLC VTY user interface will provide floating-point strings like
"23.456" while GAD stores them as micro-degress 23456000. The osmo_gad_to_str*
will also convert latitude and longitude to floating-point string.

There was code review concerns against adding this API, upon which I tried to
use floating point string formats. But I encountered various problems with
accuracy and trailing zeros. For global positioning data (latitude and
longitude), even inaccuracy on the sixth significant decimal digit causes
noticeable positional shift. To achieve sufficient accuracy on the least
significant end, I need to use double instead of float. To remove trailing
zeros, the idea was to use '%.6g' format, but that can cause rounding. '%.6f'
on a double looks ok, but always includes trailing zeros. A test program shows:

 %.6g of ((double)(int32_t)23230100)/1e6 = "23.2301"     <-- good
 %.6g of ((double)(int32_t)42419993)/1e6 = "42.42"       <-- bad rounding
 %.6g of ((double)(int32_t)23230199)/1e6 = "23.2302"     <-- bad rounding

 %.6f of ((double)(int32_t)23230100)/1e6 = "23.230100"   <-- trailing zeros
 %.6f of ((double)(int32_t)42419993)/1e6 = "42.419993"   <-- good
 %.6f of ((double)(int32_t)23230199)/1e6 = "23.230199"   <-- good

It looks like when accepting that there will be trailing zeros, using double
with '%.6f' would work out, but in the end I am not certain enough that there
aren't more hidden rounding / precision glitches. Hence I decided to reinforce
the need to add this API: it is glitch free in sufficient precision for
latitude and longitude data, because it is based on integer arithmetic.

The need for this precision is particular to the (new) OsmoSMLC vty
configuration, where reading and writing back user config must not modify the
values the user entered. Considering to add these functions to osmo-smlc.git,
we might as well add them here to libosmocore utils, and also use them in
osmo_gad_to_str_*() functions.

Change-Id: Ib9aee749cd331712a4dcdadfb6a2dfa4c26da957
---
M include/osmocom/core/utils.h
M src/utils.c
M tests/utils/utils_test.c
M tests/utils/utils_test.ok
4 files changed, 1,000 insertions(+), 0 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index 8619120..c9d5560 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -279,6 +279,10 @@
 
 bool osmo_str_startswith(const char *str, const char *startswith_str);
 
+int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision);
+int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision);
+char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision);
+
 /*! Translate a buffer function to a talloc context function.
  * This is the full function body of a char *foo_name_c(void *ctx, val...) function, implemented by an
  * int foo_name_buf(buf, buflen, val...) function:
diff --git a/src/utils.c b/src/utils.c
index 772b671..c0ab166 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <inttypes.h>
+#include <limits.h>
 
 #include <osmocom/core/utils.h>
 #include <osmocom/core/bit64gen.h>
@@ -1208,4 +1209,192 @@
 	return strncmp(str, startswith_str, strlen(startswith_str)) == 0;
 }
 
+/*! Convert a string of a floating point number to a signed int, with a decimal factor (fixed-point precision).
+ * For example, with precision=3, convert "-1.23" to -1230. In other words, the float value is multiplied by
+ * 10 to-the-power-of precision to obtain the returned integer.
+ * The usable range of digits is -INT64_MAX .. INT64_MAX -- note, not INT64_MIN! The value of INT64_MIN is excluded to
+ * reduce implementation complexity. See also utils_test.c.
+ * \param[out] val  Returned integer value.
+ * \param[in] str  String of a float, like '-12.345'.
+ * \param[in] in_len  Length of string to parse, or -1 to use strlen(str).
+ * \param[in] precision  Fixed-point precision, or  * \returns 0 on success, negative on error.
+ */
+int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision)
+{
+	const char *point;
+	char *endptr;
+	const char *p;
+	int64_t sign = 1;
+	int64_t integer = 0;
+	int64_t decimal = 0;
+	int64_t precision_factor;
+	int64_t integer_max;
+	int64_t decimal_max;
+	int i;
+
+	OSMO_ASSERT(val);
+	*val = 0;
+
+	if (!str)
+		return -EINVAL;
+	if (str[0] == '-') {
+		str = str + 1;
+		sign = -1;
+	} else if (str[0] == '+') {
+		str = str + 1;
+	}
+	if (!str[0])
+		return -EINVAL;
+
+	/* Validate entire string as purely digits and at most one decimal dot. If not doing this here in advance,
+	 * parsing digits might stop early because of precision cut-off and miss validation of input data. */
+	point = NULL;
+	for (p = str; *p; p++) {
+		if (*p == '.') {
+			if (point)
+				return -EINVAL;
+			point = p;
+		} else if (!isdigit(*p))
+			return -EINVAL;
+	}
+
+	/* Parse integer part if there is one. If the string starts with a point, there's nothing to parse for the
+	 * integer part. */
+	if (!point || point > str) {
+		errno = 0;
+		integer = strtoll(str, &endptr, 10);
+		if ((errno == ERANGE && (integer == LONG_MAX || integer == LONG_MIN))
+		    || (errno != 0 && integer == 0))
+			return -ERANGE;
+
+		if ((point && endptr != point)
+		    || (!point && *endptr))
+			return -EINVAL;
+	}
+
+	/* Parse the fractional part if there is any, and if the precision is nonzero (if we even care about fractional
+	 * digits) */
+	if (precision && point && point[1] != '\0') {
+		/* limit the number of digits parsed to 'precision'.
+		 * If 'precision' is larger than the 19 digits representable in int64_t, skip some, to pick up lower
+		 * magnitude digits. */
+		unsigned int skip_digits = (precision < 20) ? 0 : precision - 20;
+		char decimal_str[precision + 1];
+		osmo_strlcpy(decimal_str, point+1, precision+1);
+
+		/* fill with zeros to make exactly 'precision' digits */
+		for (i = strlen(decimal_str); i < precision; i++)
+			decimal_str[i] = '0';
+		decimal_str[precision] = '\0';
+
+		for (i = 0; i < skip_digits; i++) {
+			/* When skipping digits because precision > nr-of-digits-in-int64_t, they must be zero;
+			 * if there is a nonzero digit above the precision, it's -ERANGE. */
+			if (decimal_str[i] != '0')
+				return -ERANGE;
+		}
+		errno = 0;
+		decimal = strtoll(decimal_str + skip_digits, &endptr, 10);
+		if ((errno == ERANGE && (decimal == LONG_MAX || decimal == LONG_MIN))
+		    || (errno != 0 && decimal == 0))
+			return -ERANGE;
+
+		if (*endptr)
+			return -EINVAL;
+	}
+
+	if (precision > 18) {
+		/* Special case of returning more digits than fit in int64_t range, e.g.
+		 * osmo_float_str_to_int("0.0000000012345678901234567", precision=25) -> 12345678901234567. */
+		precision_factor = 0;
+		integer_max = 0;
+		decimal_max = INT64_MAX;
+	} else {
+		/* Do not surpass the resulting int64_t range. Depending on the amount of precision, the integer part
+		 * and decimal part have specific ranges they must comply to. */
+		precision_factor = 1;
+		for (i = 0; i < precision; i++)
+		     precision_factor *= 10;
+		integer_max = INT64_MAX / precision_factor;
+		if (integer == integer_max)
+			decimal_max = INT64_MAX % precision_factor;
+		else
+			decimal_max = INT64_MAX;
+	}
+
+	if (integer > integer_max)
+		return -ERANGE;
+	if (decimal > decimal_max)
+		return -ERANGE;
+
+	*val = sign * (integer * precision_factor + decimal);
+	return 0;
+}
+
+/*! Convert an integer with a factor of a million to a floating point string.
+ * For example, with precision = 3, convert -1230 to "-1.23".
+ * \param[out] buf  Buffer to write string to.
+ * \param[in] buflen  sizeof(buf).
+ * \param[in] val  Value to convert to float.
+ * \returns number of chars that would be written, like snprintf().
+ */
+int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision)
+{
+	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
+	unsigned int i;
+	unsigned int w;
+	int64_t precision_factor;
+	if (val < 0) {
+		OSMO_STRBUF_PRINTF(sb, "-");
+		if (val == INT64_MIN) {
+			OSMO_STRBUF_PRINTF(sb, "ERR");
+			return sb.chars_needed;
+		}
+		val = -val;
+	}
+
+	if (precision > 18) {
+		/* Special case of returning more digits than fit in int64_t range, e.g.
+		 * osmo_int_to_float_str(12345678901234567, precision=25) -> "0.0000000012345678901234567". */
+		if (!val) {
+			OSMO_STRBUF_PRINTF(sb, "0");
+			return sb.chars_needed;
+		}
+		OSMO_STRBUF_PRINTF(sb, "0.");
+		for (i = 19; i < precision; i++)
+			OSMO_STRBUF_PRINTF(sb, "0");
+		precision = 19;
+	} else {
+		precision_factor = 1;
+		for (i = 0; i < precision; i++)
+		     precision_factor *= 10;
+
+		OSMO_STRBUF_PRINTF(sb, "%" PRId64, val / precision_factor);
+		val %= precision_factor;
+		if (!val)
+			return sb.chars_needed;
+		OSMO_STRBUF_PRINTF(sb, ".");
+	}
+
+	/* print fractional part, skip trailing zeros */
+	w = precision;
+	while (!(val % 10)) {
+		val /= 10;
+		w--;
+	}
+	OSMO_STRBUF_PRINTF(sb, "%0*" PRId64, w, val);
+	return sb.chars_needed;
+}
+
+/*! Convert an integer with a factor of a million to a floating point string.
+ * For example, convert -1230000 to "-1.23".
+ * \param[in] ctx  Talloc ctx to allocate string buffer from.
+ * \param[in] val  Value to convert to float.
+ * \returns resulting string, dynamically allocated.
+ */
+char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision)
+{
+	OSMO_NAME_C_IMPL(ctx, 16, "ERROR", osmo_int_to_float_str_buf, val, precision)
+}
+
 /*! @} */
diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c
index 9ff023b..108bf5a 100644
--- a/tests/utils/utils_test.c
+++ b/tests/utils/utils_test.c
@@ -34,6 +34,7 @@
 #include <arpa/inet.h>
 #include <errno.h>
 #include <limits.h>
+#include <inttypes.h>
 
 static void hexdump_test(void)
 {
@@ -1443,6 +1444,446 @@
 	}
 }
 
+struct float_str_to_int_test {
+	unsigned int precision;
+	const char *str;
+	int64_t expect_val;
+	int expect_err;
+};
+struct float_str_to_int_test float_str_to_int_tests[] = {
+	{ 0, "0", 0 },
+	{ 0, "1", 1 },
+	{ 0, "12.345", 12 },
+	{ 0, "+12.345", 12 },
+	{ 0, "-12.345", -12 },
+	{ 0, "0.345", 0 },
+	{ 0, ".345", 0 },
+	{ 0, "-0.345", 0 },
+	{ 0, "-.345", 0 },
+	{ 0, "12.", 12 },
+	{ 0, "-180", -180 },
+	{ 0, "180", 180 },
+	{ 0, "360", 360 },
+	{ 0, "123.4567890123", 123 },
+	{ 0, "123.4567890123456789012345", 123 },
+	{ 0, "9223372036854775807", 9223372036854775807LL },
+	{ 0, "-9223372036854775807", -9223372036854775807LL },
+	{ 0, "-9223372036854775808", .expect_err = -ERANGE },
+	{ 0, "9223372036854775808", .expect_err = -ERANGE },
+	{ 0, "-9223372036854775809", .expect_err = -ERANGE },
+	{ 0, "100000000000000000000", .expect_err = -ERANGE },
+	{ 0, "-100000000000000000000", .expect_err = -ERANGE },
+	{ 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 0, "1.2.3", .expect_err = -EINVAL },
+	{ 0, "foo", .expect_err = -EINVAL },
+	{ 0, "1.foo", .expect_err = -EINVAL },
+	{ 0, "1.foo", .expect_err = -EINVAL },
+	{ 0, "12.-345", .expect_err = -EINVAL },
+	{ 0, "-12.-345", .expect_err = -EINVAL },
+	{ 0, "12.+345", .expect_err = -EINVAL },
+	{ 0, "+12.+345", .expect_err = -EINVAL },
+	{ 0, "", .expect_err = -EINVAL },
+	{ 0, NULL, .expect_err = -EINVAL },
+
+	{ 1, "0", 0 },
+	{ 1, "1", 10 },
+	{ 1, "12.345", 123 },
+	{ 1, "+12.345", 123 },
+	{ 1, "-12.345", -123 },
+	{ 1, "0.345", 3 },
+	{ 1, ".345", 3 },
+	{ 1, "-0.345", -3 },
+	{ 1, "-.345", -3 },
+	{ 1, "12.", 120 },
+	{ 1, "-180", -1800 },
+	{ 1, "180", 1800 },
+	{ 1, "360", 3600 },
+	{ 1, "123.4567890123", 1234 },
+	{ 1, "123.4567890123456789012345", 1234 },
+	{ 1, "922337203685477580.7", 9223372036854775807LL },
+	{ 1, "-922337203685477580.7", -9223372036854775807LL },
+	{ 1, "-922337203685477580.8", .expect_err = -ERANGE },
+	{ 1, "922337203685477580.8", .expect_err = -ERANGE },
+	{ 1, "-922337203685477580.9", .expect_err = -ERANGE },
+	{ 1, "100000000000000000000", .expect_err = -ERANGE },
+	{ 1, "-100000000000000000000", .expect_err = -ERANGE },
+	{ 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 1, "1.2.3", .expect_err = -EINVAL },
+	{ 1, "foo", .expect_err = -EINVAL },
+	{ 1, "1.foo", .expect_err = -EINVAL },
+	{ 1, "1.foo", .expect_err = -EINVAL },
+	{ 1, "12.-345", .expect_err = -EINVAL },
+	{ 1, "-12.-345", .expect_err = -EINVAL },
+	{ 1, "12.+345", .expect_err = -EINVAL },
+	{ 1, "+12.+345", .expect_err = -EINVAL },
+	{ 1, "", .expect_err = -EINVAL },
+	{ 1, NULL, .expect_err = -EINVAL },
+
+	{ 6, "0", 0 },
+	{ 6, "1", 1000000 },
+	{ 6, "12.345", 12345000 },
+	{ 6, "+12.345", 12345000 },
+	{ 6, "-12.345", -12345000 },
+	{ 6, "0.345", 345000 },
+	{ 6, ".345", 345000 },
+	{ 6, "-0.345", -345000 },
+	{ 6, "-.345", -345000 },
+	{ 6, "12.", 12000000 },
+	{ 6, "-180", -180000000 },
+	{ 6, "180", 180000000 },
+	{ 6, "360", 360000000 },
+	{ 6, "123.4567890123", 123456789 },
+	{ 6, "123.4567890123456789012345", 123456789 },
+	{ 6, "9223372036854.775807", 9223372036854775807LL },
+	{ 6, "-9223372036854.775807", -9223372036854775807LL },
+	{ 6, "-9223372036854.775808", .expect_err = -ERANGE },
+	{ 6, "9223372036854.775808", .expect_err = -ERANGE },
+	{ 6, "-9223372036854.775809", .expect_err = -ERANGE },
+	{ 6, "100000000000000000000", .expect_err = -ERANGE },
+	{ 6, "-100000000000000000000", .expect_err = -ERANGE },
+	{ 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 6, "1.2.3", .expect_err = -EINVAL },
+	{ 6, "foo", .expect_err = -EINVAL },
+	{ 6, "1.foo", .expect_err = -EINVAL },
+	{ 6, "1.foo", .expect_err = -EINVAL },
+	{ 6, "12.-345", .expect_err = -EINVAL },
+	{ 6, "-12.-345", .expect_err = -EINVAL },
+	{ 6, "12.+345", .expect_err = -EINVAL },
+	{ 6, "+12.+345", .expect_err = -EINVAL },
+	{ 6, "", .expect_err = -EINVAL },
+	{ 6, NULL, .expect_err = -EINVAL },
+
+	{ 18, "0", 0 },
+	{ 18, "1", 1000000000000000000LL },
+	{ 18, "1.2345", 1234500000000000000LL },
+	{ 18, "+1.2345", 1234500000000000000LL },
+	{ 18, "-1.2345", -1234500000000000000LL },
+	{ 18, "0.345", 345000000000000000LL },
+	{ 18, ".345", 345000000000000000LL },
+	{ 18, "-0.345", -345000000000000000LL },
+	{ 18, "-.345", -345000000000000000LL },
+	{ 18, "2.", 2000000000000000000LL },
+	{ 18, "-8", -8000000000000000000LL },
+	{ 18, "1.234567890123", 1234567890123000000LL },
+	{ 18, "1.234567890123456789012345", 1234567890123456789LL },
+	{ 18, "123.4567890123", .expect_err = -ERANGE },
+	{ 18, "9.223372036854775807", 9223372036854775807LL },
+	{ 18, "-9.223372036854775807", -9223372036854775807LL },
+	{ 18, "-9.223372036854775808", .expect_err = -ERANGE },
+	{ 18, "9.223372036854775808", .expect_err = -ERANGE },
+	{ 18, "-9.223372036854775809", .expect_err = -ERANGE },
+	{ 18, "100000000000000000000", .expect_err = -ERANGE },
+	{ 18, "-100000000000000000000", .expect_err = -ERANGE },
+	{ 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 18, "1.2.3", .expect_err = -EINVAL },
+	{ 18, "foo", .expect_err = -EINVAL },
+	{ 18, "1.foo", .expect_err = -EINVAL },
+	{ 18, "1.foo", .expect_err = -EINVAL },
+	{ 18, "12.-345", .expect_err = -EINVAL },
+	{ 18, "-12.-345", .expect_err = -EINVAL },
+	{ 18, "12.+345", .expect_err = -EINVAL },
+	{ 18, "+12.+345", .expect_err = -EINVAL },
+	{ 18, "", .expect_err = -EINVAL },
+	{ 18, NULL, .expect_err = -EINVAL },
+
+	{ 19, "0", 0 },
+	{ 19, ".1", 1000000000000000000LL },
+	{ 19, ".12345", 1234500000000000000LL },
+	{ 19, "+.12345", 1234500000000000000LL },
+	{ 19, "-.12345", -1234500000000000000LL },
+	{ 19, "0.0345", 345000000000000000LL },
+	{ 19, ".0345", 345000000000000000LL },
+	{ 19, "-0.0345", -345000000000000000LL },
+	{ 19, "-.0345", -345000000000000000LL },
+	{ 19, ".2", 2000000000000000000LL },
+	{ 19, "-.8", -8000000000000000000LL },
+	{ 19, ".1234567890123", 1234567890123000000LL },
+	{ 19, ".1234567890123456789012345", 1234567890123456789LL },
+	{ 19, "123.4567890123", .expect_err = -ERANGE },
+	{ 19, ".9223372036854775807", 9223372036854775807LL },
+	{ 19, "-.9223372036854775807", -9223372036854775807LL },
+	{ 19, "-.9223372036854775808", .expect_err = -ERANGE },
+	{ 19, ".9223372036854775808", .expect_err = -ERANGE },
+	{ 19, "-.9223372036854775809", .expect_err = -ERANGE },
+	{ 19, "100000000000000000000", .expect_err = -ERANGE },
+	{ 19, "-100000000000000000000", .expect_err = -ERANGE },
+	{ 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 19, "1.2.3", .expect_err = -EINVAL },
+	{ 19, "foo", .expect_err = -EINVAL },
+	{ 19, "1.foo", .expect_err = -EINVAL },
+	{ 19, "1.foo", .expect_err = -EINVAL },
+	{ 19, "12.-345", .expect_err = -EINVAL },
+	{ 19, "-12.-345", .expect_err = -EINVAL },
+	{ 19, "12.+345", .expect_err = -EINVAL },
+	{ 19, "+12.+345", .expect_err = -EINVAL },
+	{ 19, "", .expect_err = -EINVAL },
+	{ 19, NULL, .expect_err = -EINVAL },
+
+	{ 20, "0", 0 },
+	{ 20, ".01", 1000000000000000000LL },
+	{ 20, ".012345", 1234500000000000000LL },
+	{ 20, "+.012345", 1234500000000000000LL },
+	{ 20, "-.012345", -1234500000000000000LL },
+	{ 20, "0.00345", 345000000000000000LL },
+	{ 20, ".00345", 345000000000000000LL },
+	{ 20, "-0.00345", -345000000000000000LL },
+	{ 20, "-.00345", -345000000000000000LL },
+	{ 20, ".02", 2000000000000000000LL },
+	{ 20, "-.08", -8000000000000000000LL },
+	{ 20, ".01234567890123", 1234567890123000000LL },
+	{ 20, ".01234567890123456789012345", 1234567890123456789LL },
+	{ 20, "12.34567890123", .expect_err = -ERANGE },
+	{ 20, ".09223372036854775807", 9223372036854775807LL },
+	{ 20, "-.09223372036854775807", -9223372036854775807LL },
+	{ 20, "-.09223372036854775808", .expect_err = -ERANGE },
+	{ 20, ".09223372036854775808", .expect_err = -ERANGE },
+	{ 20, "-.09223372036854775809", .expect_err = -ERANGE },
+	{ 20, ".1", .expect_err = -ERANGE },
+	{ 20, "-.1", .expect_err = -ERANGE },
+	{ 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 20, "1.2.3", .expect_err = -EINVAL },
+	{ 20, "foo", .expect_err = -EINVAL },
+	{ 20, "1.foo", .expect_err = -EINVAL },
+	{ 20, "1.foo", .expect_err = -EINVAL },
+	{ 20, "12.-345", .expect_err = -EINVAL },
+	{ 20, "-12.-345", .expect_err = -EINVAL },
+	{ 20, "12.+345", .expect_err = -EINVAL },
+	{ 20, "+12.+345", .expect_err = -EINVAL },
+	{ 20, "", .expect_err = -EINVAL },
+	{ 20, NULL, .expect_err = -EINVAL },
+
+	{ 25, "0", 0 },
+	{ 25, ".0000001", 1000000000000000000LL },
+	{ 25, ".00000012345", 1234500000000000000LL },
+	{ 25, "+.00000012345", 1234500000000000000LL },
+	{ 25, "-.00000012345", -1234500000000000000LL },
+	{ 25, "0.0000000345", 345000000000000000LL },
+	{ 25, ".0000000345", 345000000000000000LL },
+	{ 25, "-0.0000000345", -345000000000000000LL },
+	{ 25, "-.0000000345", -345000000000000000LL },
+	{ 25, ".0000002", 2000000000000000000LL },
+	{ 25, "-.0000008", -8000000000000000000LL },
+	{ 25, ".0000001234567890123", 1234567890123000000LL },
+	{ 25, ".0000001234567890123456789012345", 1234567890123456789LL },
+	{ 25, ".0001234567890123", .expect_err = -ERANGE },
+	{ 25, ".0000009223372036854775807", 9223372036854775807LL },
+	{ 25, "-.0000009223372036854775807", -9223372036854775807LL },
+	{ 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
+	{ 25, ".0000009223372036854775808", .expect_err = -ERANGE },
+	{ 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
+	{ 25, ".000001", .expect_err = -ERANGE },
+	{ 25, "-.000001", .expect_err = -ERANGE },
+	{ 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+	{ 25, "1.2.3", .expect_err = -EINVAL },
+	{ 25, "foo", .expect_err = -EINVAL },
+	{ 25, "1.foo", .expect_err = -EINVAL },
+	{ 25, "1.foo", .expect_err = -EINVAL },
+	{ 25, "12.-345", .expect_err = -EINVAL },
+	{ 25, "-12.-345", .expect_err = -EINVAL },
+	{ 25, "12.+345", .expect_err = -EINVAL },
+	{ 25, "+12.+345", .expect_err = -EINVAL },
+	{ 25, "", .expect_err = -EINVAL },
+	{ 25, NULL, .expect_err = -EINVAL },
+};
+const char *errno_str(int rc)
+{
+	if (rc == -EINVAL)
+		return "=-EINVAL";
+	if (rc == -ERANGE)
+		return "=-ERANGE";
+	return "";
+}
+void test_float_str_to_int()
+{
+	const struct float_str_to_int_test *t;
+	printf("--- %s\n", __func__);
+	for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
+		int rc;
+		int64_t val;
+		rc = osmo_float_str_to_int(&val, t->str, t->precision);
+		printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
+		       osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
+
+		if (rc != t->expect_err)
+			printf("  ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
+		if (val != t->expect_val)
+			printf("  ERROR: expected val=%" PRId64 "\n", t->expect_val);
+		if (rc != t->expect_err||val != t->expect_val)
+		exit(0);
+	}
+}
+
+struct int_to_float_str_test {
+	unsigned int precision;
+	int64_t val;
+	const char *expect_str;
+};
+struct int_to_float_str_test int_to_float_str_tests[] = {
+	{ 0, 0, "0" },
+	{ 0, 1, "1" },
+	{ 0, 1000000, "1000000" },
+	{ 0, -1000000, "-1000000" },
+	{ 0, 1000001, "1000001" },
+	{ 0, -1000001, "-1000001" },
+	{ 0, 1000100, "1000100" },
+	{ 0, -1010000, "-1010000" },
+	{ 0, 1100000, "1100000" },
+	{ 0, 10000000, "10000000" },
+	{ 0, -10000000, "-10000000" },
+	{ 0, 100000000, "100000000" },
+	{ 0, -100000000, "-100000000" },
+	{ 0, 9223372036854775807, "9223372036854775807" },
+	{ 0, -9223372036854775807, "-9223372036854775807" },
+	{ 0, INT64_MIN, "-ERR" },
+
+	{ 1, 0, "0" },
+	{ 1, 1, "0.1" },
+	{ 1, 1000000, "100000" },
+	{ 1, -1000000, "-100000" },
+	{ 1, 1000001, "100000.1" },
+	{ 1, -1000001, "-100000.1" },
+	{ 1, 1000100, "100010" },
+	{ 1, -1010000, "-101000" },
+	{ 1, 1100000, "110000" },
+	{ 1, 10000000, "1000000" },
+	{ 1, -10000000, "-1000000" },
+	{ 1, 100000000, "10000000" },
+	{ 1, -100000000, "-10000000" },
+	{ 1, 9223372036854775807, "922337203685477580.7" },
+	{ 1, -9223372036854775807, "-922337203685477580.7" },
+	{ 1, INT64_MIN, "-ERR" },
+
+	{ 3, 0, "0" },
+	{ 3, 1, "0.001" },
+	{ 3, 1000000, "1000" },
+	{ 3, -1000000, "-1000" },
+	{ 3, 1000001, "1000.001" },
+	{ 3, -1000001, "-1000.001" },
+	{ 3, 1000100, "1000.1" },
+	{ 3, -1010000, "-1010" },
+	{ 3, 1100000, "1100" },
+	{ 3, 10000000, "10000" },
+	{ 3, -10000000, "-10000" },
+	{ 3, 100000000, "100000" },
+	{ 3, -100000000, "-100000" },
+	{ 3, 9223372036854775807, "9223372036854775.807" },
+	{ 3, -9223372036854775807, "-9223372036854775.807" },
+	{ 3, INT64_MIN, "-ERR" },
+
+	{ 6, 0, "0" },
+	{ 6, 1, "0.000001" },
+	{ 6, 1000000, "1" },
+	{ 6, -1000000, "-1" },
+	{ 6, 1000001, "1.000001" },
+	{ 6, -1000001, "-1.000001" },
+	{ 6, 1000100, "1.0001" },
+	{ 6, -1010000, "-1.01" },
+	{ 6, 1100000, "1.1" },
+	{ 6, 10000000, "10" },
+	{ 6, -10000000, "-10" },
+	{ 6, 100000000, "100" },
+	{ 6, -100000000, "-100" },
+	{ 6, 9223372036854775807, "9223372036854.775807" },
+	{ 6, -9223372036854775807, "-9223372036854.775807" },
+	{ 6, INT64_MIN, "-ERR" },
+
+	{ 17, 0, "0" },
+	{ 17, 1, "0.00000000000000001" },
+	{ 17, 1000000, "0.00000000001" },
+	{ 17, -1000000, "-0.00000000001" },
+	{ 17, 1000001, "0.00000000001000001" },
+	{ 17, -1000001, "-0.00000000001000001" },
+	{ 17, 1000100, "0.000000000010001" },
+	{ 17, -1010000, "-0.0000000000101" },
+	{ 17, 1100000, "0.000000000011" },
+	{ 17, 10000000, "0.0000000001" },
+	{ 17, -10000000, "-0.0000000001" },
+	{ 17, 100000000, "0.000000001" },
+	{ 17, -100000000, "-0.000000001" },
+	{ 17, 9223372036854775807, "92.23372036854775807" },
+	{ 17, -9223372036854775807, "-92.23372036854775807" },
+	{ 17, INT64_MIN, "-ERR" },
+
+	{ 18, 0, "0" },
+	{ 18, 1, "0.000000000000000001" },
+	{ 18, 1000000, "0.000000000001" },
+	{ 18, -1000000, "-0.000000000001" },
+	{ 18, 1000001, "0.000000000001000001" },
+	{ 18, -1000001, "-0.000000000001000001" },
+	{ 18, 1000100, "0.0000000000010001" },
+	{ 18, -1010000, "-0.00000000000101" },
+	{ 18, 1100000, "0.0000000000011" },
+	{ 18, 10000000, "0.00000000001" },
+	{ 18, -10000000, "-0.00000000001" },
+	{ 18, 100000000, "0.0000000001" },
+	{ 18, -100000000, "-0.0000000001" },
+	{ 18, 9223372036854775807, "9.223372036854775807" },
+	{ 18, -9223372036854775807, "-9.223372036854775807" },
+	{ 18, INT64_MIN, "-ERR" },
+
+	{ 19, 0, "0" },
+	{ 19, 1, "0.0000000000000000001" },
+	{ 19, 1000000, "0.0000000000001" },
+	{ 19, -1000000, "-0.0000000000001" },
+	{ 19, 1000001, "0.0000000000001000001" },
+	{ 19, -1000001, "-0.0000000000001000001" },
+	{ 19, 1000100, "0.00000000000010001" },
+	{ 19, -1010000, "-0.000000000000101" },
+	{ 19, 1100000, "0.00000000000011" },
+	{ 19, 10000000, "0.000000000001" },
+	{ 19, -10000000, "-0.000000000001" },
+	{ 19, 100000000, "0.00000000001" },
+	{ 19, -100000000, "-0.00000000001" },
+	{ 19, 9223372036854775807, "0.9223372036854775807" },
+	{ 19, -9223372036854775807, "-0.9223372036854775807" },
+	{ 19, INT64_MIN, "-ERR" },
+
+	{ 23, 0, "0" },
+	{ 23, 1, "0.00000000000000000000001" },
+	{ 23, 1000000, "0.00000000000000001" },
+	{ 23, -1000000, "-0.00000000000000001" },
+	{ 23, 1000001, "0.00000000000000001000001" },
+	{ 23, -1000001, "-0.00000000000000001000001" },
+	{ 23, 1000100, "0.000000000000000010001" },
+	{ 23, -1010000, "-0.0000000000000000101" },
+	{ 23, 1100000, "0.000000000000000011" },
+	{ 23, 10000000, "0.0000000000000001" },
+	{ 23, -10000000, "-0.0000000000000001" },
+	{ 23, 100000000, "0.000000000000001" },
+	{ 23, -100000000, "-0.000000000000001" },
+	{ 23, 9223372036854775807, "0.00009223372036854775807" },
+	{ 23, -9223372036854775807, "-0.00009223372036854775807" },
+	{ 23, INT64_MIN, "-ERR" },
+};
+void test_int_to_float_str()
+{
+	const struct int_to_float_str_test *t;
+	printf("--- %s\n", __func__);
+	for (t = int_to_float_str_tests;
+	     (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
+	     t++) {
+		char buf[128];
+		int rc;
+		rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
+		printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
+		       osmo_quote_str(buf, -1));
+
+		if (rc != strlen(buf))
+			printf("  ERROR: expected rc=%zu\n", strlen(buf));
+		if (strcmp(buf, t->expect_str))
+			printf("  ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
+		if (rc != strlen(buf) || strcmp(buf, t->expect_str))
+			exit(0);
+	}
+}
+
 int main(int argc, char **argv)
 {
 	static const struct log_info log_info = {};
@@ -1468,5 +1909,7 @@
 	name_c_impl_test();
 	osmo_print_n_test();
 	osmo_strnchr_test();
+	test_float_str_to_int();
+	test_int_to_float_str();
 	return 0;
 }
diff --git a/tests/utils/utils_test.ok b/tests/utils/utils_test.ok
index f1b07fa..0c71b8f 100644
--- a/tests/utils/utils_test.ok
+++ b/tests/utils/utils_test.ok
@@ -505,3 +505,367 @@
 osmo_strnchr("foo=bar", 0, '=') -> -1
 osmo_strnchr("foo", 9, '=') -> -1
 osmo_strnchr("foo", 9, '\0') -> 3
+--- test_float_str_to_int
+osmo_float_str_to_int("0", 0) -> rc=0 val=0
+osmo_float_str_to_int("1", 0) -> rc=0 val=1
+osmo_float_str_to_int("12.345", 0) -> rc=0 val=12
+osmo_float_str_to_int("+12.345", 0) -> rc=0 val=12
+osmo_float_str_to_int("-12.345", 0) -> rc=0 val=-12
+osmo_float_str_to_int("0.345", 0) -> rc=0 val=0
+osmo_float_str_to_int(".345", 0) -> rc=0 val=0
+osmo_float_str_to_int("-0.345", 0) -> rc=0 val=0
+osmo_float_str_to_int("-.345", 0) -> rc=0 val=0
+osmo_float_str_to_int("12.", 0) -> rc=0 val=12
+osmo_float_str_to_int("-180", 0) -> rc=0 val=-180
+osmo_float_str_to_int("180", 0) -> rc=0 val=180
+osmo_float_str_to_int("360", 0) -> rc=0 val=360
+osmo_float_str_to_int("123.4567890123", 0) -> rc=0 val=123
+osmo_float_str_to_int("123.4567890123456789012345", 0) -> rc=0 val=123
+osmo_float_str_to_int("9223372036854775807", 0) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9223372036854775807", 0) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9223372036854775808", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9223372036854775808", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9223372036854775809", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 1) -> rc=0 val=0
+osmo_float_str_to_int("1", 1) -> rc=0 val=10
+osmo_float_str_to_int("12.345", 1) -> rc=0 val=123
+osmo_float_str_to_int("+12.345", 1) -> rc=0 val=123
+osmo_float_str_to_int("-12.345", 1) -> rc=0 val=-123
+osmo_float_str_to_int("0.345", 1) -> rc=0 val=3
+osmo_float_str_to_int(".345", 1) -> rc=0 val=3
+osmo_float_str_to_int("-0.345", 1) -> rc=0 val=-3
+osmo_float_str_to_int("-.345", 1) -> rc=0 val=-3
+osmo_float_str_to_int("12.", 1) -> rc=0 val=120
+osmo_float_str_to_int("-180", 1) -> rc=0 val=-1800
+osmo_float_str_to_int("180", 1) -> rc=0 val=1800
+osmo_float_str_to_int("360", 1) -> rc=0 val=3600
+osmo_float_str_to_int("123.4567890123", 1) -> rc=0 val=1234
+osmo_float_str_to_int("123.4567890123456789012345", 1) -> rc=0 val=1234
+osmo_float_str_to_int("922337203685477580.7", 1) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-922337203685477580.7", 1) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-922337203685477580.8", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("922337203685477580.8", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-922337203685477580.9", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 6) -> rc=0 val=0
+osmo_float_str_to_int("1", 6) -> rc=0 val=1000000
+osmo_float_str_to_int("12.345", 6) -> rc=0 val=12345000
+osmo_float_str_to_int("+12.345", 6) -> rc=0 val=12345000
+osmo_float_str_to_int("-12.345", 6) -> rc=0 val=-12345000
+osmo_float_str_to_int("0.345", 6) -> rc=0 val=345000
+osmo_float_str_to_int(".345", 6) -> rc=0 val=345000
+osmo_float_str_to_int("-0.345", 6) -> rc=0 val=-345000
+osmo_float_str_to_int("-.345", 6) -> rc=0 val=-345000
+osmo_float_str_to_int("12.", 6) -> rc=0 val=12000000
+osmo_float_str_to_int("-180", 6) -> rc=0 val=-180000000
+osmo_float_str_to_int("180", 6) -> rc=0 val=180000000
+osmo_float_str_to_int("360", 6) -> rc=0 val=360000000
+osmo_float_str_to_int("123.4567890123", 6) -> rc=0 val=123456789
+osmo_float_str_to_int("123.4567890123456789012345", 6) -> rc=0 val=123456789
+osmo_float_str_to_int("9223372036854.775807", 6) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9223372036854.775807", 6) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9223372036854.775808", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9223372036854.775808", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9223372036854.775809", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 18) -> rc=0 val=0
+osmo_float_str_to_int("1", 18) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int("1.2345", 18) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+1.2345", 18) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-1.2345", 18) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.345", 18) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".345", 18) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.345", 18) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.345", 18) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("2.", 18) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-8", 18) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int("1.234567890123", 18) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int("1.234567890123456789012345", 18) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("123.4567890123", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9.223372036854775807", 18) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9.223372036854775807", 18) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9.223372036854775808", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9.223372036854775808", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9.223372036854775809", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 19) -> rc=0 val=0
+osmo_float_str_to_int(".1", 19) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".12345", 19) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.12345", 19) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.12345", 19) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.0345", 19) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".0345", 19) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.0345", 19) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.0345", 19) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".2", 19) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.8", 19) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".1234567890123", 19) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".1234567890123456789012345", 19) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("123.4567890123", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".9223372036854775807", 19) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.9223372036854775807", 19) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.9223372036854775808", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".9223372036854775808", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.9223372036854775809", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 20) -> rc=0 val=0
+osmo_float_str_to_int(".01", 20) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".012345", 20) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.012345", 20) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.012345", 20) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.00345", 20) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".00345", 20) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.00345", 20) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.00345", 20) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".02", 20) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.08", 20) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".01234567890123", 20) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".01234567890123456789012345", 20) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("12.34567890123", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".09223372036854775807", 20) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.09223372036854775807", 20) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.09223372036854775808", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".09223372036854775808", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.09223372036854775809", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".1", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.1", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 25) -> rc=0 val=0
+osmo_float_str_to_int(".0000001", 25) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".00000012345", 25) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.00000012345", 25) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.00000012345", 25) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.0000000345", 25) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".0000000345", 25) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.0000000345", 25) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.0000000345", 25) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".0000002", 25) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.0000008", 25) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".0000001234567890123", 25) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".0000001234567890123456789012345", 25) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int(".0001234567890123", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".0000009223372036854775807", 25) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.0000009223372036854775807", 25) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.0000009223372036854775808", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".0000009223372036854775808", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.0000009223372036854775809", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".000001", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.000001", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 25) -> rc=-22=-EINVAL val=0
+--- test_int_to_float_str
+osmo_int_to_float_str_buf(0, 0) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 0) -> rc=1 str="1"
+osmo_int_to_float_str_buf(1000000, 0) -> rc=7 str="1000000"
+osmo_int_to_float_str_buf(-1000000, 0) -> rc=8 str="-1000000"
+osmo_int_to_float_str_buf(1000001, 0) -> rc=7 str="1000001"
+osmo_int_to_float_str_buf(-1000001, 0) -> rc=8 str="-1000001"
+osmo_int_to_float_str_buf(1000100, 0) -> rc=7 str="1000100"
+osmo_int_to_float_str_buf(-1010000, 0) -> rc=8 str="-1010000"
+osmo_int_to_float_str_buf(1100000, 0) -> rc=7 str="1100000"
+osmo_int_to_float_str_buf(10000000, 0) -> rc=8 str="10000000"
+osmo_int_to_float_str_buf(-10000000, 0) -> rc=9 str="-10000000"
+osmo_int_to_float_str_buf(100000000, 0) -> rc=9 str="100000000"
+osmo_int_to_float_str_buf(-100000000, 0) -> rc=10 str="-100000000"
+osmo_int_to_float_str_buf(9223372036854775807, 0) -> rc=19 str="9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 0) -> rc=20 str="-9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 0) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 1) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 1) -> rc=3 str="0.1"
+osmo_int_to_float_str_buf(1000000, 1) -> rc=6 str="100000"
+osmo_int_to_float_str_buf(-1000000, 1) -> rc=7 str="-100000"
+osmo_int_to_float_str_buf(1000001, 1) -> rc=8 str="100000.1"
+osmo_int_to_float_str_buf(-1000001, 1) -> rc=9 str="-100000.1"
+osmo_int_to_float_str_buf(1000100, 1) -> rc=6 str="100010"
+osmo_int_to_float_str_buf(-1010000, 1) -> rc=7 str="-101000"
+osmo_int_to_float_str_buf(1100000, 1) -> rc=6 str="110000"
+osmo_int_to_float_str_buf(10000000, 1) -> rc=7 str="1000000"
+osmo_int_to_float_str_buf(-10000000, 1) -> rc=8 str="-1000000"
+osmo_int_to_float_str_buf(100000000, 1) -> rc=8 str="10000000"
+osmo_int_to_float_str_buf(-100000000, 1) -> rc=9 str="-10000000"
+osmo_int_to_float_str_buf(9223372036854775807, 1) -> rc=20 str="922337203685477580.7"
+osmo_int_to_float_str_buf(-9223372036854775807, 1) -> rc=21 str="-922337203685477580.7"
+osmo_int_to_float_str_buf(-9223372036854775808, 1) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 3) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 3) -> rc=5 str="0.001"
+osmo_int_to_float_str_buf(1000000, 3) -> rc=4 str="1000"
+osmo_int_to_float_str_buf(-1000000, 3) -> rc=5 str="-1000"
+osmo_int_to_float_str_buf(1000001, 3) -> rc=8 str="1000.001"
+osmo_int_to_float_str_buf(-1000001, 3) -> rc=9 str="-1000.001"
+osmo_int_to_float_str_buf(1000100, 3) -> rc=6 str="1000.1"
+osmo_int_to_float_str_buf(-1010000, 3) -> rc=5 str="-1010"
+osmo_int_to_float_str_buf(1100000, 3) -> rc=4 str="1100"
+osmo_int_to_float_str_buf(10000000, 3) -> rc=5 str="10000"
+osmo_int_to_float_str_buf(-10000000, 3) -> rc=6 str="-10000"
+osmo_int_to_float_str_buf(100000000, 3) -> rc=6 str="100000"
+osmo_int_to_float_str_buf(-100000000, 3) -> rc=7 str="-100000"
+osmo_int_to_float_str_buf(9223372036854775807, 3) -> rc=20 str="9223372036854775.807"
+osmo_int_to_float_str_buf(-9223372036854775807, 3) -> rc=21 str="-9223372036854775.807"
+osmo_int_to_float_str_buf(-9223372036854775808, 3) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 6) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 6) -> rc=8 str="0.000001"
+osmo_int_to_float_str_buf(1000000, 6) -> rc=1 str="1"
+osmo_int_to_float_str_buf(-1000000, 6) -> rc=2 str="-1"
+osmo_int_to_float_str_buf(1000001, 6) -> rc=8 str="1.000001"
+osmo_int_to_float_str_buf(-1000001, 6) -> rc=9 str="-1.000001"
+osmo_int_to_float_str_buf(1000100, 6) -> rc=6 str="1.0001"
+osmo_int_to_float_str_buf(-1010000, 6) -> rc=5 str="-1.01"
+osmo_int_to_float_str_buf(1100000, 6) -> rc=3 str="1.1"
+osmo_int_to_float_str_buf(10000000, 6) -> rc=2 str="10"
+osmo_int_to_float_str_buf(-10000000, 6) -> rc=3 str="-10"
+osmo_int_to_float_str_buf(100000000, 6) -> rc=3 str="100"
+osmo_int_to_float_str_buf(-100000000, 6) -> rc=4 str="-100"
+osmo_int_to_float_str_buf(9223372036854775807, 6) -> rc=20 str="9223372036854.775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 6) -> rc=21 str="-9223372036854.775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 6) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 17) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 17) -> rc=19 str="0.00000000000000001"
+osmo_int_to_float_str_buf(1000000, 17) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-1000000, 17) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(1000001, 17) -> rc=19 str="0.00000000001000001"
+osmo_int_to_float_str_buf(-1000001, 17) -> rc=20 str="-0.00000000001000001"
+osmo_int_to_float_str_buf(1000100, 17) -> rc=17 str="0.000000000010001"
+osmo_int_to_float_str_buf(-1010000, 17) -> rc=16 str="-0.0000000000101"
+osmo_int_to_float_str_buf(1100000, 17) -> rc=14 str="0.000000000011"
+osmo_int_to_float_str_buf(10000000, 17) -> rc=12 str="0.0000000001"
+osmo_int_to_float_str_buf(-10000000, 17) -> rc=13 str="-0.0000000001"
+osmo_int_to_float_str_buf(100000000, 17) -> rc=11 str="0.000000001"
+osmo_int_to_float_str_buf(-100000000, 17) -> rc=12 str="-0.000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 17) -> rc=20 str="92.23372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 17) -> rc=21 str="-92.23372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 17) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 18) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 18) -> rc=20 str="0.000000000000000001"
+osmo_int_to_float_str_buf(1000000, 18) -> rc=14 str="0.000000000001"
+osmo_int_to_float_str_buf(-1000000, 18) -> rc=15 str="-0.000000000001"
+osmo_int_to_float_str_buf(1000001, 18) -> rc=20 str="0.000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 18) -> rc=21 str="-0.000000000001000001"
+osmo_int_to_float_str_buf(1000100, 18) -> rc=18 str="0.0000000000010001"
+osmo_int_to_float_str_buf(-1010000, 18) -> rc=17 str="-0.00000000000101"
+osmo_int_to_float_str_buf(1100000, 18) -> rc=15 str="0.0000000000011"
+osmo_int_to_float_str_buf(10000000, 18) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-10000000, 18) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(100000000, 18) -> rc=12 str="0.0000000001"
+osmo_int_to_float_str_buf(-100000000, 18) -> rc=13 str="-0.0000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 18) -> rc=20 str="9.223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 18) -> rc=21 str="-9.223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 18) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 19) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 19) -> rc=21 str="0.0000000000000000001"
+osmo_int_to_float_str_buf(1000000, 19) -> rc=15 str="0.0000000000001"
+osmo_int_to_float_str_buf(-1000000, 19) -> rc=16 str="-0.0000000000001"
+osmo_int_to_float_str_buf(1000001, 19) -> rc=21 str="0.0000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 19) -> rc=22 str="-0.0000000000001000001"
+osmo_int_to_float_str_buf(1000100, 19) -> rc=19 str="0.00000000000010001"
+osmo_int_to_float_str_buf(-1010000, 19) -> rc=18 str="-0.000000000000101"
+osmo_int_to_float_str_buf(1100000, 19) -> rc=16 str="0.00000000000011"
+osmo_int_to_float_str_buf(10000000, 19) -> rc=14 str="0.000000000001"
+osmo_int_to_float_str_buf(-10000000, 19) -> rc=15 str="-0.000000000001"
+osmo_int_to_float_str_buf(100000000, 19) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-100000000, 19) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 19) -> rc=21 str="0.9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 19) -> rc=22 str="-0.9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 19) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 23) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 23) -> rc=25 str="0.00000000000000000000001"
+osmo_int_to_float_str_buf(1000000, 23) -> rc=19 str="0.00000000000000001"
+osmo_int_to_float_str_buf(-1000000, 23) -> rc=20 str="-0.00000000000000001"
+osmo_int_to_float_str_buf(1000001, 23) -> rc=25 str="0.00000000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 23) -> rc=26 str="-0.00000000000000001000001"
+osmo_int_to_float_str_buf(1000100, 23) -> rc=23 str="0.000000000000000010001"
+osmo_int_to_float_str_buf(-1010000, 23) -> rc=22 str="-0.0000000000000000101"
+osmo_int_to_float_str_buf(1100000, 23) -> rc=20 str="0.000000000000000011"
+osmo_int_to_float_str_buf(10000000, 23) -> rc=18 str="0.0000000000000001"
+osmo_int_to_float_str_buf(-10000000, 23) -> rc=19 str="-0.0000000000000001"
+osmo_int_to_float_str_buf(100000000, 23) -> rc=17 str="0.000000000000001"
+osmo_int_to_float_str_buf(-100000000, 23) -> rc=18 str="-0.000000000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 23) -> rc=25 str="0.00009223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 23) -> rc=26 str="-0.00009223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 23) -> rc=4 str="-ERR"

-- 
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/20331
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ib9aee749cd331712a4dcdadfb6a2dfa4c26da957
Gerrit-Change-Number: 20331
Gerrit-PatchSet: 4
Gerrit-Owner: neels <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de>
Gerrit-CC: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201008/e854172f/attachment.htm>


More information about the gerrit-log mailing list