Skip to content

Extended maths#403

Open
systemcrash wants to merge 18 commits intojow-:masterfrom
systemcrash:ext_maths
Open

Extended maths#403
systemcrash wants to merge 18 commits intojow-:masterfrom
systemcrash:ext_maths

Conversation

@systemcrash
Copy link
Copy Markdown
Contributor

A range of math functions found in math.h are now exposed for use. A few functions could be trivially written in ucode, but their inclusion here makes any resulting ucode more compact, less error prone (helps us abdicate thinking) and results in a more comprehensive math library.

The net growth is roughly +5KB.

@jow-
Copy link
Copy Markdown
Owner

jow- commented Apr 24, 2026

I wonder if it would be beneficial to let ceil, round, floor and trunc return an integer instead of a double. I think in most contexts these functions are used to produce an integer result.

@jow-
Copy link
Copy Markdown
Owner

jow- commented Apr 24, 2026

The min() and max() functions overlap with min() and max(), respectively.

@systemcrash
Copy link
Copy Markdown
Contributor Author

I wonder if it would be beneficial to let ceil, round, floor and trunc return an integer instead of a double. I think in most contexts these functions are used to produce an integer result.

I contemplated this, although I kept with consistency to return the same type as parameters (double in double out). e.g. https://en.cppreference.com/c/numeric/math/trunc - in ucode, type coercion is trivial, so I suppose having an int wouldn't hurt.

Additionally, I could document the types as double instead of generic number.

The min() and max() functions overlap with min() and max(), respectively.

I missed that.

Suggestion: the maths versions be called fmin/fmax since it uses those from math.h?

using fmin and fmax which take double values.

grows math lib by 48 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
using fmin and fmax

grows math lib by 32 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
sign - uses simple logic cast where true is 1 and false is 0.
signbit - follows IEEE-754 behaviour (-0.0 returns -1)
signnz - returns either -1/1.

grows math lib by 80 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
grows math lib by 24 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Finds the largest integer value not greater than x.

grows math lib by 40 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Computes the smallest integer value not less than x.

grows math lib by 24 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
round x down or up to nearest integer value.

grows math lib by 24 bytes.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
truncate away the decimal portion of a floating point number to
produce an integral number.

grows math lib by 24 bytes.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
log10 and log2

grows math lib by 136 bytes.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
-p == JSON rendering
-e == string rendering

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
boolean check to determine whether value is Infinity.

grows math lib by 40 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Direct function equivalent to sin(x) / cos (x).

grows math lib by 64 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
arccosine, arcsine, and arctangent functions.

grows math lib by 208 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
hyperbolic cosine, hyperbolic sine, and hyperbolic tangent functions.

grows math lib by 4296 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
cube root and hypotenuse functions

grows math lib by 136 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
@jow-
Copy link
Copy Markdown
Owner

jow- commented Apr 24, 2026

You could keep the math versions as min() and max() - question is rather whether we accept the redundancy or not. One could think of math.min() and math.max() as a restricted "fast" subset of core.min() and core.max(), but question is how useful this is. The core version is variadic for example while the math version is not, making it somewhat unusable to e.g. find the global minimum or maximum of an array, dimishing the usefulness of their "fast" or "numeric only" property somewhat.

About the trunc() et al return value type: boils down what the most common use case and context is. Some thoughts:

  • When outputting doubles, one most commonly specifies a precision:

    • printf("%.2f", trunc(val)) -> and int return value wouldn't hurt
  • When rounding doubles, one probably wants to use them as int:

    • ival = int(round(val)) -> extra function call overhead required to get a true int out of a rounded double
  • When using rounded double values in calculations involving other doubles the VM would automatically coerce

    • val = floor(val) * 1.5 -> int result wouldn't hurt and immediately get coerced back

Another consideration is that small int results could be stored in tagged pointers, a double result will always require a heap allocation (8 + 8 bytes)

@systemcrash
Copy link
Copy Markdown
Contributor Author

OK - I made those output integers. I added a boolean flag which toggles output type for floor/ceil/round/trunc (which has the benefit of retaining -0.0 which seems relevant in some maths and int types cannot represent); int output is default.

I renamed min/max -> fmin/fmax. I think they're OK to have since their behaviour mirrors that of math.h which aligns with usage expectations, although admittedly finding the min/max in an array does seem to have more utility.

expm1(x) computes exp(x) - 1 accurately for small x

log1p(x) computes log(1 + x) accurately

grows math lib by 152 bytes

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
links now resolve

* as multiply needs space so it is not interpreted as italic formatting.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
default (false) when flag not provided is int64 output
set flag to true to output double

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
@systemcrash
Copy link
Copy Markdown
Contributor Author

Out of curiosity, I benchmarked the main and math variants for a million rounds each:

math variant

import { fmin, fmax } from 'math';

for (let i = 0; i < 1000000; i++) {
        let x = fmin(3, 4);
}

for (let i = 0; i < 1000000; i++) {
        let x = fmax(4, 3);
}

main variant

for (let i = 0; i < 1000000; i++) {
        let x = min(3, 4);
}

for (let i = 0; i < 1000000; i++) {
        let x = max(4, 3);
}

outputs showed a varied but distinct difference:

> time ./ucode -l math ./minmax.uc

________________________________________________________
Executed in  687.27 millis    fish           external
   usr time  664.94 millis    0.21 millis  664.74 millis
   sys time   17.17 millis    2.28 millis   14.89 millis

> time ./ucode ./minmaxmain.uc

________________________________________________________
Executed in  769.92 millis    fish           external
   usr time  747.36 millis    0.23 millis  747.13 millis
   sys time   16.77 millis    2.70 millis   14.07 millis

@systemcrash
Copy link
Copy Markdown
Contributor Author

trunc variants showed a ~10% speed improvement to output int vs double.

int

import { trunc } from 'math';

for (let i = 0; i < 1000000; i++) {
        trunc(2.73);
}

double

import { trunc } from 'math';

for (let i = 0; i < 1000000; i++) {
        trunc(2.73, true);
}

output:

> time ./ucode -l math ./truncint.uc

________________________________________________________
Executed in  349.31 millis    fish           external
   usr time  325.66 millis    0.25 millis  325.40 millis
   sys time   17.66 millis    2.53 millis   15.13 millis

> time ./ucode -l math ./truncd.uc

________________________________________________________
Executed in  386.23 millis    fish           external
   usr time  361.50 millis    0.26 millis  361.24 millis
   sys time   20.16 millis    2.87 millis   17.29 millis

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants