-
Notifications
You must be signed in to change notification settings - Fork 64
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
Add Floating
class
#457
Add Floating
class
#457
Conversation
library/arith.lisp
Outdated
|
||
(%define-floating-functions Single-Float cl:single-float) | ||
(%define-floating-functions Double-Float cl:double-float) | ||
(%define-floating-functions (Complex Single-Float) (cl:complex cl:single-float)) |
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.
These should be (cl:or cl:single-float (cl:complex cl:single-float))
.
See (typep #C(1 0) '(complex 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.
Those are only used to coerce pi at the moment, and actually it seems that coercing pi as either single-float
or (complex single-float)
work equally well. However, one cannot (coerce pi '(or single-float (complex single-foat))
. However, if we don't coerce pi, it will sometimes decide it wants be a double-float
.
Given the option of (coerce pi 'single-float) => 3.14...
and (coerce pi '(complex single-float)) ;=> #C(3.14... 0)
do think there is a best choice?
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 either is fine. I misunderstood the use case.
I left a few questions about the granularity & specific details of the type constraints above. I think it's worth distinguishing between two uses of typeclasses (perhaps there are others):
This PR appears to be sensitive to both of these items, which is good. I would say that I would be surprised to see serious numeric code which is generic across substantially different domains (e.g. which works effectively for both complex double floats & real matrices), so I don't think it's worth sweating that part too much. |
@kilimanjaro If you had other comments, I don't think they saved. |
library/arith.lisp
Outdated
(coalton-toplevel | ||
(define-class (Exponent :a) | ||
"Exponential functions where exp is exponentiation of Euler's number and | ||
(exp (+ a b)) = (* (exp a) (exp b)) and (exp 0) = 1." |
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.
Should I take this to mean that :a
is a member of some other typeclass (providing arithmetic and 0, 1)?
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.
Yeah, I figured Num would imply commutative, but we could easily add it.
library/arith.lisp
Outdated
(exp (+ a b)) = (* (exp a) (exp b)) and (exp 0) = 1." | ||
(exp (:a -> :a))) | ||
|
||
(define-class (Exponent :a => Logarithm :a) |
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.
Out of curiosity, do you have something in mind that would be an instance of Exponent
but not Logarithm
?
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.
No specific examples, but if we end up splitting the class like this I think exp would be the most useful function. I guess for the cases were either ln(X) doesn't converge but e^X does - it could just throw an error (or in the case were the implementer is too lazy).
library/arith.lisp
Outdated
(atanh (:a -> :a))) | ||
|
||
(define-class ((InvTrig :a) (Num :a) => Floating :a) | ||
"Common floating point operations." |
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.
To be a bit pedantic here, I don't quite see what makes this a floating type. For example, one could imagine implementing all of these with fixed point arithmetic. Also, unless I'm missing something, it could even be satisfied by symbolic expressions (this is perhaps a silly thing to mention).
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'm happy if anyone has any better names. I just was trying to keep it somewhat friendly to Haskell-familiar users.
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 makes sense. No real objections then.
library/arith.lisp
Outdated
"Logarithmic functions such that log is the inverse of exp." | ||
(log (:a -> :a))) | ||
|
||
(define-class ((Exponent :a) (Dividable :a :a) => Trig :a) |
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.
It's not clear why we need (Dividable :a :a)
. There's no comparable constraint placed on Exponent
or Logarithm
.
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'm not aware of a way to define tan without division, but I could be wrong. I could also move tan to Floating
and remove Dividable
.
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.
a power series doesn't require division
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 love it how my brain decided the only way to compute tan was sin/cos and just pretended tan didn't have a series representation.
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.
when @kilimanjaro computes tan he uses a compass and ruler; i've seen it with my own two eyes
library/arith.lisp
Outdated
(cosh (:a -> :a)) | ||
(tanh (:a -> :a))) | ||
|
||
(define-class ((Logarithm :a) (Trig :a) => InvTrig :a) |
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.
Similarly here; it's not clear why we need Logarithm
. To me it sort of implies that these inverse trig functions can be defined in terms of log, which they can, but you need complex arithmetic for that, and also it's probably not how anybody would want to implement them.
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.
Yeah, I was trying to instill some semblance of hierarchy, but I agree this one perhaps is just restrictive with no benefit.
(define (acosh x) (lisp ,coalton-type (x) (cl:acosh x))) | ||
(define (atanh x) (lisp ,coalton-type (x) (cl:atanh x)))) | ||
|
||
(define-instance (Floating ,coalton-type) |
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.
Perhaps abs
is worth adding here.
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 already have abs
for instances of Ord
, but perhaps modulus
or absolute
? Or we could change abs
for Ord to something like positive
. However, I have code were I need Complex numbers as a vector space (for dot products), likewise I have been using norm
on Complex numbers. But implementing linear algebra code is probably out of scope for this PR.
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.
It strikes me as a bit odd that abs
requires Ord
, for the reason that you mentioned: one will end up defining a modulus
or absolute
or something for complex numbers. So if we do have the ability to move stuff around, I suggest dropping the Ord
constraint.
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.
yeah, abs in ord seems weird. I think haskell does it but I would be fine nixing it.
While I was waiting on #451, I actually wasn't too unhappy with having Floating being split into multiple segments. This would allow more flexible instances (e.g. square matrices via power series). We could also move (a)tan(h) to Floating if we wanted to remove Dividable from Trig. I put
**
andlogBase
intoFloating
as well because giving them a multi parameter type class messes with stuff likelogBase 2 2.0
- even though a power series of e^x or log x imply power series a^x or log_a x resp. One can also come up with a power series forsqrt
, so I really haven't broken it up to allow all the mathematical edge-cases.I'll be the first to admit this seems a bit advanced for a standard library, so I'm happy to make floating into a mega class when #451 gets sorted out. Either way, I'd love some input.
Fixes: #366