strutil: add method to get an sr_rational from a string
The method accepts strings with numbers in scientific or normal notation, e.g. -1.25 or 3.37e-6. The numeric range is limited by the sr_rational range, i.e +-9.2e18, resolution is ~19 digits.
This commit is contained in:
parent
510aa8281f
commit
5ec172d7e9
|
@ -226,6 +226,7 @@ SR_API uint64_t sr_parse_timestring(const char *timestring);
|
||||||
SR_API gboolean sr_parse_boolstring(const char *boolstring);
|
SR_API gboolean sr_parse_boolstring(const char *boolstring);
|
||||||
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
|
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
|
||||||
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
|
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
|
||||||
|
SR_API int sr_parse_rational(const char *str, struct sr_rational *ret);
|
||||||
|
|
||||||
/*--- version.c -------------------------------------------------------------*/
|
/*--- version.c -------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,77 @@ SR_PRIV int sr_atof_ascii(const char *str, float *ret)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string representation of a numeric value to a @sr_rational. The
|
||||||
|
* conversion is strict and will fail if the complete string does not represent
|
||||||
|
* a valid number. The function sets errno according to the details of the
|
||||||
|
* failure. This version ignores the locale.
|
||||||
|
*
|
||||||
|
* @param str The string representation to convert.
|
||||||
|
* @param ret Pointer to sr_rational where the result of the conversion will be stored.
|
||||||
|
*
|
||||||
|
* @retval SR_OK Conversion successful.
|
||||||
|
* @retval SR_ERR Failure.
|
||||||
|
*
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
|
||||||
|
{
|
||||||
|
char *endptr = NULL;
|
||||||
|
int64_t integral;
|
||||||
|
int64_t fractional = 0;
|
||||||
|
int64_t denominator = 1;
|
||||||
|
int32_t fractional_len = 0;
|
||||||
|
int32_t exponent = 0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
integral = g_ascii_strtoll(str, &endptr, 10);
|
||||||
|
|
||||||
|
if (errno)
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
if (*endptr == '.') {
|
||||||
|
const char* start = endptr + 1;
|
||||||
|
fractional = g_ascii_strtoll(start, &endptr, 10);
|
||||||
|
if (errno)
|
||||||
|
return SR_ERR;
|
||||||
|
fractional_len = endptr - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*endptr == 'E') || (*endptr == 'e')) {
|
||||||
|
exponent = g_ascii_strtoll(endptr + 1, &endptr, 10);
|
||||||
|
if (errno)
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*endptr != '\0')
|
||||||
|
return SR_ERR;
|
||||||
|
|
||||||
|
for (int i = 0; i < fractional_len; i++)
|
||||||
|
integral *= 10;
|
||||||
|
exponent -= fractional_len;
|
||||||
|
|
||||||
|
if (integral >= 0)
|
||||||
|
integral += fractional;
|
||||||
|
else
|
||||||
|
integral -= fractional;
|
||||||
|
|
||||||
|
while (exponent > 0) {
|
||||||
|
integral *= 10;
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (exponent < 0) {
|
||||||
|
denominator *= 10;
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->p = integral;
|
||||||
|
ret->q = denominator;
|
||||||
|
|
||||||
|
return SR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a numeric value value to its "natural" string representation
|
* Convert a numeric value value to its "natural" string representation
|
||||||
* in SI units.
|
* in SI units.
|
||||||
|
|
|
@ -34,6 +34,18 @@ static void test_samplerate(uint64_t samplerate, const char *expected)
|
||||||
g_free(s);
|
g_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_rational(const char *input, struct sr_rational expected)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct sr_rational rational;
|
||||||
|
|
||||||
|
ret = sr_parse_rational(input, &rational);
|
||||||
|
fail_unless(ret == SR_OK);
|
||||||
|
fail_unless((expected.p == rational.p) && (expected.q == rational.q),
|
||||||
|
"Invalid result for '%s': %ld/%ld'.",
|
||||||
|
input, rational.p, rational.q);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check various inputs for sr_samplerate_string():
|
* Check various inputs for sr_samplerate_string():
|
||||||
*
|
*
|
||||||
|
@ -155,6 +167,41 @@ START_TEST(test_ghz)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_integral)
|
||||||
|
{
|
||||||
|
test_rational("1", (struct sr_rational){1, 1});
|
||||||
|
test_rational("2", (struct sr_rational){2, 1});
|
||||||
|
test_rational("10", (struct sr_rational){10, 1});
|
||||||
|
test_rational("-255", (struct sr_rational){-255, 1});
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_fractional)
|
||||||
|
{
|
||||||
|
test_rational("0.1", (struct sr_rational){1, 10});
|
||||||
|
test_rational("1.0", (struct sr_rational){10, 10});
|
||||||
|
test_rational("1.2", (struct sr_rational){12, 10});
|
||||||
|
test_rational("12.34", (struct sr_rational){1234, 100});
|
||||||
|
test_rational("-12.34", (struct sr_rational){-1234, 100});
|
||||||
|
test_rational("10.00", (struct sr_rational){1000, 100});
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_exponent)
|
||||||
|
{
|
||||||
|
test_rational("1e0", (struct sr_rational){1, 1});
|
||||||
|
test_rational("1E0", (struct sr_rational){1, 1});
|
||||||
|
test_rational("1E1", (struct sr_rational){10, 1});
|
||||||
|
test_rational("1e-1", (struct sr_rational){1, 10});
|
||||||
|
test_rational("-1.234e-0", (struct sr_rational){-1234, 1000});
|
||||||
|
test_rational("-1.234e3", (struct sr_rational){-1234, 1});
|
||||||
|
test_rational("-1.234e-3", (struct sr_rational){-1234, 1000000});
|
||||||
|
test_rational("0.001e3", (struct sr_rational){1, 1});
|
||||||
|
test_rational("0.001e0", (struct sr_rational){1, 1000});
|
||||||
|
test_rational("0.001e-3", (struct sr_rational){1, 1000000});
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
Suite *suite_strutil(void)
|
Suite *suite_strutil(void)
|
||||||
{
|
{
|
||||||
Suite *s;
|
Suite *s;
|
||||||
|
@ -168,6 +215,9 @@ Suite *suite_strutil(void)
|
||||||
tcase_add_test(tc, test_khz);
|
tcase_add_test(tc, test_khz);
|
||||||
tcase_add_test(tc, test_mhz);
|
tcase_add_test(tc, test_mhz);
|
||||||
tcase_add_test(tc, test_ghz);
|
tcase_add_test(tc, test_ghz);
|
||||||
|
tcase_add_test(tc, test_integral);
|
||||||
|
tcase_add_test(tc, test_fractional);
|
||||||
|
tcase_add_test(tc, test_exponent);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
Loading…
Reference in New Issue