lambda-calculus/number/set_str.c
2025-01-13 20:36:07 -06:00

142 lines
2.6 KiB
C

#include <assert.h>
#include <debug.h>
#include <misc/wcindex.h>
#include <extern/gmp/mini-mpq.h>
#include "struct.h"
#include "set_str.h"
void number_set_str(
struct number* this,
const wchar_t* text)
{
// "text" might be binary, octal, hexadecimal, or a float.
// "text" might contain a decimal point. Hopefully just one.
ENTER;
assert(text);
assert(*text);
dpvws(text);
mpq_t base;
mpq_init(base);
const wchar_t* start = text;
if (*start != L'0')
{
mpq_set_ui(base, 10, 1);
}
else switch (start[1])
{
case L'x':
mpq_set_ui(base, 16, 1), start += 2;
break;
case L'b':
mpq_set_ui(base, 2, 1), start += 2;
break;
default:
mpq_set_ui(base, 8, 1);
break;
}
mpq_ptr result = this->number;
// initalize result to 0.
mpq_set_ui(result, 0, 1);
const wchar_t* dot = wcindex(text, L'.');
// parse whole number:
{
const wchar_t* end = dot ? dot - 1 : start + wcslen(start) - 1;
assert(start <= end);
mpq_t multiplier, digit;
mpq_init(multiplier);
mpq_init(digit);
mpq_set_ui(multiplier, 1, 1);
while (start <= end)
{
wchar_t e = *end--;
dpvc(e);
assert(e >= L'0');
mpq_set_ui(digit, (unsigned) (e - '0'), 1);
mpq_mul(digit, digit, multiplier);
mpq_add(result, result, digit);
mpq_mul(multiplier, multiplier, base);
}
mpq_clear(multiplier);
mpq_clear(digit);
}
if (dot)
{
const wchar_t* moving = dot + 1;
dpvws(moving);
mpq_t multiplier, digit;
mpq_init(multiplier);
mpq_init(digit);
mpq_set_ui(multiplier, 1, 1);
mpq_div(multiplier, multiplier, base);
while (*moving)
{
wchar_t e = *moving++;
dpvwc(e);
assert(e >= '0');
mpq_set_ui(digit, (unsigned) (e - '0'), 1);
mpq_mul(digit, digit, multiplier);
mpq_add(result, result, digit);
mpq_div(multiplier, multiplier, base);
}
mpq_clear(multiplier);
mpq_clear(digit);
}
mpq_clear(base);
EXIT;
}