-
-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Math functions #645
Math functions #645
Conversation
The gamma function is pretty hairy — not defined for negative integers. Easier to just define these functions the “dumb” way. Reimplemented `falling_factorial` without the gamma function Reimplemented `binom` in terms of `falling_factorial` and `factorial` (so that it now perfectly matches the binomial series) Updated descriptions accordingly Added tests of new functions Rebuilt book
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Thank you very much. Just a few minor comments.
use math::transcendental | ||
|
||
@name("Factorial") | ||
@description("The product of the integers 1 through n, also written n!") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use $…$
to embed LaTeX formulas in @description
s. This way, they render more nicely in the online documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this was your intent, but I think we could state more clearly that Numbat also supports !
as an operator for factorials.
@description("Equal to n⋅(n-1)⋅…⋅(n-k+2)⋅(n-k+1) (k terms total). If n is an integer, this is the number | ||
of k-element permutations from a set of size n. k must always be an integer.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this whitespace lead to problems in the rendered output? I think you can have multiple @description
fields and they will be concatenated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple @description
fields are concatenated with newlines between them, which I'm not sure I want. But then again the literal newline is picked up in the string, so there may not be a way to get this stored as a single line while writing it across multiple lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separately, this has me wondering whether there would be merit in having separate @description
s for docs and for numbat CLI. I would like to write that product as $n\cdot(n-1)\cdot\ldots\cdot(n-k+2)\cdot(n-k+1)$
for the docs, but I wouldn't want to have to read that in the CLI. (Is there a LaTeX-to-unicode compiler?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this partially in #512 but didn't come to a satisfactory conclusion so far. I think the best to do as of now would be to use a math block but directly use the Unicode characters instead of their LaTeX commands (e.g $n⋅(n−1)⋅…⋅(n−k+2)⋅(n−k+1)$
in this case). MathJax handles this well as far as I can tell and it is also decently readable as plain text.
of k-element permutations from a set of size n. k must always be an integer.") | ||
@url("https://en.wikipedia.org/wiki/Falling_and_rising_factorials") | ||
fn falling_factorial(n: Scalar, k: Scalar) -> Scalar = | ||
if k < 0 || fract(k) != 0 then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have is_non_negative
. Maybe we should also add is_integer
and use both functions here (and below)?
numbat/modules/core/numbers.nbt
Outdated
@example("is_int(30 seconds)") | ||
@example("is_int(0.5 minutes)") | ||
fn is_int<D: Dim>(value: D) -> Bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be a function on Scalar
. If we make it work on dimensionful quantities, it introduces inconsistencies, as you demonstrated in the example:
true = is_int(30 seconds) ?=? is_int(0.5 minutes) = false
We should avoid this if possible (I know that there are already ways to introduce inconsistencies like this via value_of
; but those functions are at least marked "unsafe").
Minor: I'd like to rename it to is_integer
Also, can we implement it in Numbat, using fract
?
fn is_integer(value: Scalar) -> Bool = is_zero(fract(value))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do. What is the benefit of implementing functions in Numbat over Rust?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good question.
I think of the "FFI bridge" between Rust and Numbat as something that helps Numbat to get up on its feet. We will always need support from the "runtime". We will probably never implement our own PRNG to implement rand
in Numbat. We will almost certainly never have a full networking stack to be able to look up currency exchange rates from within Numbat. And we will never implement print
in Numbat.
But as Numbat grows into a more mature language of its own, I think it makes sense to keep the foreign-function interface as small as possible. Especially in areas which belong to the core functionality of Numbat like mathematical computations.
Having part of the "standard library" written in Numbat itself helps us to design APIs in a way that makes them easy to use … in Numbat itself. #646 is a good example. If all string functions were written in Rust and re-exported to Numbat, may we wouldn't have found out that they are not as ergonomic as they could be.
The standard library is the biggest Numbat "code base" that we have, and it's a good "benchmark" to have when we make changes to the language.
There are also practical advantages to having functions implemented in Numbat itself. Even if we reimplement something that would be readily available in Rust, it's typically way less code to maintain. The function name appears just once in the fn …
definition instead of multiple times for a FFI function. It also allows us to change/develop functions without having to recompile the Numbat interpreter.
There's also downsides of course. Performance, for example. If we see that a heavily-used function is too slow, we can think about re-implementing it in Rust.
Side remark: Note that there are also some functions like map
that can't even be implemented in Rust at the moment, as we don't have a way to call other Numbat functions from FFI functions.
Renamed `is_int` to `is_integer` Implemented in Numbat instead of Rust, removed Rust implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
I made some choices of function names and functionality (e.g.,
binom
taking non integer args). Let me know what you think.