change how numbers are stored so they are in an efficent binary format, able to be quickly read by the runtime

This commit is contained in:
William Bell
2025-08-12 00:13:01 +01:00
parent f851b37f99
commit d4528e44f6
13 changed files with 126 additions and 72 deletions

File diff suppressed because one or more lines are too long

View File

@@ -104,7 +104,7 @@ int mpq_set_decimal_str_exp(mpq_t r, const char *str) {
return -1;
}
if (endptr-exp_str>11) {
if (endptr - exp_str > 11) {
free(buf);
return -1;
}
@@ -176,19 +176,17 @@ int mpq_set_decimal_str_exp(mpq_t r, const char *str) {
ParsedValueReturn parse_number(Token *token, char *path) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_NUMBER;
mpq_t r;
mpq_init(r);
int err = mpq_set_decimal_str_exp(r, token->value);
mpq_t *r_ptr = malloc(sizeof(mpq_t));
mpq_init(*r_ptr);
int err = mpq_set_decimal_str_exp(*r_ptr, token->value);
if (err) {
free_parsed(parsedValue);
free(parsedValue);
mpq_clear(r);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, path, "Parsing Error",
"Unable to parse number"),
NULL};
}
char *s = mpq_get_str(NULL, 62, r);
mpq_clear(r);
parsedValue->data = s;
parsedValue->data = r_ptr;
return (ParsedValueReturn){no_err, parsedValue};
}

View File

@@ -22,6 +22,7 @@
#include "operations/operations.h"
#include "return/return.h"
#include "string/string.h"
#include <gmp-x86_64.h>
#include <gmp.h>
#include <stdbool.h>
#include <stddef.h>
@@ -220,6 +221,7 @@ void free_parsed(void *ptr) {
free_identifier(parsed);
break;
case AST_NUMBER:
mpq_clear(*(mpq_t *)parsed->data);
free(parsed->data);
break;
case AST_STRING:

View File

@@ -15,10 +15,10 @@
ArgonObject *ARGON_NUMBER_TYPE;
#include <gmp.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
/* change SIGNIFICANT_DIGITS to taste (15 mimics double-ish behaviour) */
#define SIGNIFICANT_DIGITS 15
@@ -36,7 +36,8 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
/* If denominator == 1, print numerator as full integer */
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
char *num_str = mpz_get_str(NULL, 10, mpq_numref(*num)); /* malloc'd by GMP */
char *num_str =
mpz_get_str(NULL, 10, mpq_numref(*num)); /* malloc'd by GMP */
ArgonObject *result = new_string_object_null_terminated(num_str);
free(num_str);
return result;
@@ -48,7 +49,8 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
mpf_set_q(f, *num); /* set mpf from mpq */
mp_exp_t exp; /* exponent returned by mpf_get_str */
/* Request SIGNIFICANT_DIGITS significant digits. If you want "max accurate", pass 0. */
/* Request SIGNIFICANT_DIGITS significant digits. If you want "max accurate",
* pass 0. */
char *mant = mpf_get_str(NULL, &exp, 10, SIGNIFICANT_DIGITS, f);
/* For zero, mpf_get_str returns an empty string and exp == 0 per GMP docs. */
if (mant == NULL) {
@@ -72,21 +74,28 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
}
size_t L = strlen(digits); /* number of digit characters returned */
/* mpf_get_str represents value as 0.digits * 10^exp (i.e. assumed decimal point after the leading zero) */
/* For scientific-format exponent (1.d..eE) we use scientific_exponent = exp - 1 */
/* mpf_get_str represents value as 0.digits * 10^exp (i.e. assumed decimal
* point after the leading zero) */
/* For scientific-format exponent (1.d..eE) we use scientific_exponent = exp -
* 1 */
long scientific_exp = (long)exp - 1L;
/* Decide whether to use fixed or scientific, mimic C's %g rule:
use scientific if exponent < -4 or exponent >= SIGNIFICANT_DIGITS */
int use_scientific = (scientific_exp < -4) || (scientific_exp >= SIGNIFICANT_DIGITS);
int use_scientific =
(scientific_exp < -4) || (scientific_exp >= SIGNIFICANT_DIGITS);
/* Build output into dynamic buffer */
/* Worst-case: sign + 1 digit + '.' + (SIGNIFICANT_DIGITS-1) digits + 'e' + sign + exponent digits + NUL */
size_t buf_size = (size_t) (negative ? 1 : 0) + 1 + 1 + (SIGNIFICANT_DIGITS - 1) + 1 + 1 + 32 + 1;
/* For fixed form we may need more if exp > L (we append zeros). Allocate a bit extra. */
/* Worst-case: sign + 1 digit + '.' + (SIGNIFICANT_DIGITS-1) digits + 'e' +
* sign + exponent digits + NUL */
size_t buf_size = (size_t)(negative ? 1 : 0) + 1 + 1 +
(SIGNIFICANT_DIGITS - 1) + 1 + 1 + 32 + 1;
/* For fixed form we may need more if exp > L (we append zeros). Allocate a
* bit extra. */
if (!use_scientific) {
/* maximum integer digits = max(exp, L) but exp could be large; be conservative */
buf_size += (size_t) ((exp > (mp_exp_t)L) ? (size_t)exp : L) + 16;
/* maximum integer digits = max(exp, L) but exp could be large; be
* conservative */
buf_size += (size_t)((exp > (mp_exp_t)L) ? (size_t)exp : L) + 16;
}
char *out = malloc(buf_size);
if (!out) {
@@ -102,7 +111,8 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
}
if (use_scientific) {
/* scientific: d.dddddeE where d = digits[0], fractional = digits[1..L-1] */
/* scientific: d.dddddeE where d = digits[0], fractional = digits[1..L-1]
*/
*p++ = digits[0];
if (L > 1) {
*p++ = '.';
@@ -111,10 +121,12 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
}
/* append exponent */
int written = snprintf(p, buf_size - (p - out), "e%+ld", scientific_exp);
if (written < 0) written = 0;
if (written < 0)
written = 0;
p += written;
} else {
/* fixed form: move decimal point right by 'exp' places in 0.digits * 10^exp */
/* fixed form: move decimal point right by 'exp' places in 0.digits * 10^exp
*/
/* integer part length = exp (may be <=0 meaning 0) */
long int_len = (long)exp;
if (int_len <= 0) {
@@ -122,12 +134,14 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
*p++ = '0';
*p++ = '.';
/* need (-int_len) leading zeros after decimal */
for (long i = 0; i < -int_len; ++i) *p++ = '0';
for (long i = 0; i < -int_len; ++i)
*p++ = '0';
/* then digits */
memcpy(p, digits, L);
p += L;
} else {
/* integer part uses first int_len digits of digits (if available), else digits plus zeros */
/* integer part uses first int_len digits of digits (if available), else
* digits plus zeros */
if ((size_t)int_len <= L) {
/* put first int_len digits as integer part */
memcpy(p, digits, (size_t)int_len);
@@ -142,7 +156,8 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
/* digits provide only part of integer, append zeros */
memcpy(p, digits, L);
p += L;
for (long i = 0; i < int_len - (long)L; ++i) *p++ = '0';
for (long i = 0; i < int_len - (long)L; ++i)
*p++ = '0';
/* no fractional part */
}
}
@@ -171,7 +186,7 @@ void create_ARGON_NUMBER_TYPE() {
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
z->_mp_alloc = limbs_count;
z->_mp_size = 0;
z->_mp_d = GC_MALLOC(limbs_count * sizeof(mp_limb_t));
z->_mp_d = ar_alloc(limbs_count * sizeof(mp_limb_t));
}
void mpq_init_gc_managed(mpq_t q, size_t num_limbs, size_t den_limbs) {
@@ -194,7 +209,7 @@ void mpq_copy_to_gc(mpq_t dest, const mpq_t src) {
}
mpq_t *mpq_new_gc_from(const mpq_t src) {
mpq_t *dest = GC_MALLOC(sizeof(mpq_t));
mpq_t *dest = ar_alloc(sizeof(mpq_t));
size_t num_limbs = (size_t)mpq_numref(src)->_mp_alloc;
size_t den_limbs = (size_t)mpq_denref(src)->_mp_alloc;
@@ -205,14 +220,35 @@ mpq_t *mpq_new_gc_from(const mpq_t src) {
return dest;
}
ArgonObject *new_number_object(char *data) {
ArgonObject *new_number_object(mpq_t number) {
ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE);
object->type = TYPE_NUMBER;
mpq_t z;
mpq_init(z);
mpq_set_str(z, data, 62);
object->value.as_number = mpq_new_gc_from(z);
mpq_clear(z);
object->value.as_number = mpq_new_gc_from(number);
return object;
}
}
void load_number(Translated *translated, RuntimeState *state) {
uint8_t to_register = pop_byte(translated, state);
size_t num_size = pop_bytecode(translated, state);
size_t num_pos = pop_bytecode(translated, state);
size_t den_size = pop_bytecode(translated, state);
size_t den_pos = pop_bytecode(translated, state);
mpq_t r;
mpq_init(r);
mpz_t num;
mpz_init(num);
mpz_import(num, num_size, 1, 1, 0, 0,
arena_get(&translated->constants, num_pos));
mpq_set_num(r, num);
mpz_clear(num);
mpz_t den;
mpz_init(den);
mpz_import(den, den_size, 1, 1, 0, 0,
arena_get(&translated->constants, den_pos));
mpq_set_den(r, den);
mpz_clear(den);
state->registers[to_register] = new_number_object(r);
mpq_clear(r);
}

View File

@@ -12,6 +12,8 @@ extern ArgonObject *ARGON_NUMBER_TYPE;
void create_ARGON_NUMBER_TYPE();
ArgonObject *new_number_object(char *data);
ArgonObject *new_number_object(mpq_t number);
void load_number(Translated *translated, RuntimeState *state);
#endif // RUNTIME_NUMBER_H

View File

@@ -14,11 +14,11 @@
#include "internals/hashmap/hashmap.h"
#include "objects/functions/functions.h"
#include "objects/literals/literals.h"
#include "objects/number/number.h"
#include "objects/object.h"
#include "objects/string/string.h"
#include "objects/term/term.h"
#include "objects/type/type.h"
#include "objects/number/number.h"
#include <fcntl.h>
#include <gc/gc.h>
#include <inttypes.h>
@@ -327,20 +327,12 @@ uint64_t pop_bytecode(Translated *translated, RuntimeState *state) {
void load_const(Translated *translated, RuntimeState *state) {
uint64_t to_register = pop_byte(translated, state);
types type = pop_byte(translated, state);
size_t length = pop_bytecode(translated, state);
uint64_t offset = pop_bytecode(translated, state);
void *data = ar_alloc_atomic(length);
memcpy(data, arena_get(&translated->constants, offset), length);
ArgonObject *object = ARGON_NULL;
switch (type) {
case TYPE_OP_STRING:
object = new_string_object(data, length);
break;
case TYPE_OP_NUMBER:
object = new_number_object(data);
}
ArgonObject *object = new_string_object(data, length);
state->registers[to_register] = object;
}
@@ -391,9 +383,12 @@ ArErr run_instruction(Translated *translated, RuntimeState *state,
case OP_LOAD_NULL:
state->registers[pop_byte(translated, state)] = ARGON_NULL;
break;
case OP_LOAD_CONST:
case OP_LOAD_STRING:
load_const(translated, state);
break;
case OP_LOAD_NUMBER:
load_number(translated,state);
break;
case OP_LOAD_FUNCTION:
load_argon_function(translated, state, *stack);
break;

View File

@@ -8,14 +8,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
all opcodes are uint8_t, and all operands are uint64_t unless marked with an asterisk (*), where it is marked as uint8_t
## OP_LOAD_CONST
## OP_LOAD_STRING
loads and initialises a value from the constant buffer into the provided register.
loads and initialises a string from the constant buffer into the provided register.
this operation 4 operands.
1. the register to write to. (*)
2. the type of data from the constant buffer. (*)
3. the length of the data in the constant buffer.
4. the offset in the constant buffer.
@@ -119,6 +118,16 @@ loads a boolean into register 1
1. byte representing true or false (1 or 0) *
## OP_LOAD_NUMBER
loads a mpq_t number into memory
1. the register to write to. (*)
3. the size of the numerator in the constant buffer.
4. the offset in the constant buffer of the numerator.
3. the size of the denominator in the constant buffer.
4. the offset in the constant buffer of the denominator.
## OP_SWAP_REGISTERS
swap the contents in two registers

View File

@@ -4,23 +4,39 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "../translator.h"
#include "number.h"
#include "../translator.h"
#include <gmp.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register) {
size_t length = strlen(number_str)+1;
size_t number_pos = arena_push(&translated->constants, number_str, length);
set_registers(translated, to_register+1);
size_t start = push_instruction_byte(translated, OP_LOAD_CONST);
push_instruction_byte(translated, to_register);
size_t translate_parsed_number(Translated *translated, mpq_t *number,
size_t to_register) {
mpz_t num, den;
mpz_init(num);
mpz_init(den);
mpz_set(num, mpq_numref(*number));
mpz_set(den, mpq_denref(*number));
size_t num_size;
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, num);
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
free(num_data);
mpz_clear(num);
// Export denominator
size_t den_size;
void *den_data = mpz_export(NULL, &den_size, 1, 1, 0, 0, den);
size_t denominator_pos =
arena_push(&translated->constants, den_data, den_size);
free(den_data);
mpz_clear(den);
set_registers(translated, to_register + 1);
push_instruction_byte(translated, TYPE_OP_NUMBER);
push_instruction_code(translated,length);
push_instruction_code(translated, number_pos);
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
push_instruction_byte(translated, to_register);
push_instruction_code(translated, num_size);
push_instruction_code(translated, numerator_pos);
push_instruction_code(translated, den_size);
push_instruction_code(translated, denominator_pos);
return start;
}

View File

@@ -8,6 +8,7 @@
#define BYTECODE_NUMBER_H
#include "../translator.h"
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register);
size_t translate_parsed_number(Translated *translated, mpq_t *number,
size_t to_register);
#endif

View File

@@ -13,9 +13,8 @@
size_t translate_parsed_string(Translated *translated, ParsedString parsedString) {
size_t string_pos = arena_push(&translated->constants, parsedString.string, parsedString.length);
set_registers(translated, 1);
size_t start = push_instruction_byte(translated, OP_LOAD_CONST);
size_t start = push_instruction_byte(translated, OP_LOAD_STRING);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, TYPE_OP_STRING);
push_instruction_code(translated,parsedString.length);
push_instruction_code(translated, string_pos);
return start;

View File

@@ -127,7 +127,7 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue, ArErr*
return translate_parsed_declaration(translated,
*((DArray *)parsedValue->data), err);
case AST_NUMBER:
return translate_parsed_number(translated, (char *)parsedValue->data, 0);
return translate_parsed_number(translated, (mpq_t*)parsedValue->data, 0);
case AST_NULL:
set_registers(translated, 1);
size_t output = push_instruction_byte(translated, OP_LOAD_NULL);

View File

@@ -15,7 +15,7 @@
#include <stdint.h>
typedef enum {
OP_LOAD_CONST,
OP_LOAD_STRING,
OP_DECLARE,
OP_LOAD_NULL,
OP_LOAD_FUNCTION,
@@ -30,9 +30,9 @@ typedef enum {
OP_CALL,
OP_SOURCE_LOCATION,
OP_LOAD_ACCESS_FUNCTION,
OP_LOAD_BOOL
OP_LOAD_BOOL,
OP_LOAD_NUMBER
} OperationType;
typedef enum { TYPE_OP_STRING, TYPE_OP_NUMBER } types;
void arena_resize(ConstantArena *arena, size_t new_size);

View File

@@ -1,2 +1,2 @@
let x = 1e1000000000
let x = 1e10000
term.log(x)