When you use ME_AUTO as the output dtype in me_compile(), miniexpr automatically infers the result type. For constants in expressions, the type is inferred from your variables.
Constants inherit the type of the first variable when output dtype is ME_AUTO.
This ensures type consistency and prevents unexpected type promotions.
// Input: float32 array
float data[] = {1.0f, 2.0f, 3.0f, 4.0f};
// Variable with explicit dtype
me_variable vars[] = {{"x", ME_FLOAT32}};
// Expression with constant
me_expr *expr = NULL;
if (me_compile("x + 3.0", vars, 1, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Result: Constants inferred as FLOAT32
// me_get_dtype(expr) returns ME_FLOAT32 ✓- You specify variable
xasME_FLOAT32 - You use
ME_AUTOfor output - miniexpr infers constant
3.0asFLOAT32(matching variable type) - Result is
FLOAT32(no unexpected promotion to FLOAT64)
This is especially important for:
// Working with single-precision arrays
float positions[1000000]; // 4MB instead of 8MB
me_variable vars[] = {{"pos", ME_FLOAT32}};
me_expr *expr = NULL;
if (me_compile("pos * 2.5 + 1.0", vars, 1, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Constants 2.5 and 1.0 are FLOAT32
// Result is FLOAT32 → saves memory!# Python/NumPy code
import numpy as np
data = np.array([1, 2, 3], dtype=np.float32) # float32 array
# miniexpr with ME_AUTO matches this dtype
# Constants in "data + 3.0" are treated as float32Many hardware accelerators work best with consistent types:
// All FLOAT32 → can use SIMD instructions
float a[N], result[N];
me_variable vars[] = {{"a", ME_FLOAT32}};
me_expr *expr = NULL;
if (me_compile("sqrt(a*a + 2.5)", vars, 1, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Entire computation in FLOAT32 → faster on GPU/SIMDIf you want different behavior, specify the output dtype explicitly. There are two modes:
When all variables are ME_AUTO and you specify an output dtype, all variables use that type:
// All variables use FLOAT64 (homogeneous)
me_variable vars[] = {{"x"}, {"y"}}; // Both ME_AUTO
me_expr *expr = NULL;
if (me_compile("x + y", vars, 2, ME_FLOAT64, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Result: FLOAT64 (all variables treated as FLOAT64)When variables have explicit types and you specify an output dtype, variables keep their types during computation, and the result is cast to the output type:
// Variables keep their types, result is cast to FLOAT64
me_variable vars[] = {{"x", ME_FLOAT32}, {"y", ME_FLOAT32}};
me_expr *expr = NULL;
if (me_compile("x + 3.0", vars, 2, ME_FLOAT64, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Computation: FLOAT32 + FLOAT32 → FLOAT32
// Output: Cast to FLOAT64
// Result: FLOAT64 (cast from FLOAT32 computation)This is useful for:
- Memory efficiency: Compute in FLOAT32, output in FLOAT64 when needed
- Heterogeneous inputs: Mixed types (INT32 + FLOAT64) with specific output requirements
- Type safety: Explicit control over both input and output types
See examples/08_explicit_output_dtype.c for complete examples.
me_variable vars[] = {
{"temperature", ME_FLOAT32},
{"pressure", ME_FLOAT32}
};
me_expr *expr = NULL;
if (me_compile("temperature * 1.8 + 32.0", vars, 1, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Constants match variable type → consistent FLOAT32me_variable vars[] = {
{"count", ME_INT32},
{"price", ME_FLOAT64}
};
me_expr *expr = NULL;
if (me_compile("count * price * 1.08", vars, 2, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Constants infer from first variable (INT32)
// But expression promotes to FLOAT64 due to mixed types
// Result: FLOAT64 ✓// DON'T DO THIS:
me_variable vars[] = {{"x"}}; // No dtype specified!
me_expr *expr = NULL;
if (me_compile("x + 3.0", vars, 1, ME_AUTO, &err, &expr) != ME_COMPILE_SUCCESS) { /* handle error */ }
// Ambiguous: what type is x? what type is 3.0?| Scenario | Variable Dtype | Output Dtype | Constant Type | Result Type |
|---|---|---|---|---|
| Float32 + const | ME_FLOAT32 |
ME_AUTO |
FLOAT32 |
FLOAT32 ✓ |
| Float64 + const | ME_FLOAT64 |
ME_AUTO |
FLOAT64 |
FLOAT64 ✓ |
| Int32 + const | ME_INT32 |
ME_AUTO |
INT32 |
INT32 ✓ |
| Float32 + const | ME_FLOAT32 |
ME_FLOAT64 |
FLOAT64 |
FLOAT64 ✓ |
| Mixed types | Both explicit | ME_AUTO |
Matches 1st var | Promoted as needed ✓ |
| All ME_AUTO | All ME_AUTO |
ME_FLOAT64 |
FLOAT64 |
FLOAT64 ✓ (homogeneous) |
| Explicit vars | Both explicit | ME_FLOAT32 |
Matches vars | FLOAT32 ✓ (cast) |
examples/03_mixed_types.c- Complete example with ME_AUTOexamples/08_explicit_output_dtype.c- Explicit variable types + explicit outputdoc/data-types.md- Full type system documentationtests/test_constant_type_inference.c- Test validating this behavior