Project

General

Profile

Actions

Feature #18179

open

Add Math methods to Numeric

Added by ankane (Andrew Kane) about 3 years ago. Updated over 2 years ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:105349]

Description

Hi, I wanted to get thoughts on adding class methods from Math as instance methods on Numeric.

x.sqrt # vs Math.sqrt(x)
x.log  # vs Math.log(x)

Rust takes this approach and it (subjectively) feels more intuitive/object-oriented. It also seems more consistent with methods like x.abs.


Related issues 1 (1 open0 closed)

Has duplicate Ruby master - Feature #18477: Float#sqrt and Integer#sqrtOpenActions

Updated by duerst (Martin Dürst) about 3 years ago

I support this. x.sqrt is indeed more object-oriented that Math.sqrt x. In an earlier discussion, it was pointed out that for Mathematicians, sqrt(x) is more natural than x.sqrt. Mathematicians can still use that notation, but also having the object-oriented notation in Ruby would indeed be great.

Updated by mrkn (Kenta Murata) about 3 years ago

I'm negative to this proposal. I don't think Math.sqrt is the behavior or the property of a Numeric object. It is the positive square root function that maps from/to the set of non-negative real numbers.

If we introduce Numeric#sqrt, we should expand its domain to negative numbers and Complex numbers. Also, it is better to consider other kinds of numbers, such as Quaternion.

Actions #3

Updated by mame (Yusuke Endoh) almost 3 years ago

Updated by duerst (Martin Dürst) over 2 years ago

mrkn (Kenta Murata) wrote in #note-2:

I'm negative to this proposal. I don't think Math.sqrt is the behavior or the property of a Numeric object. It is the positive square root function that maps from/to the set of non-negative real numbers.

This is how Mathematicians think, and we don't want to take this possibility away from them. But Ruby is mainly for Ruby programmers. And most Ruby programmers may not think like Mathematicians. Ruby programmers should be able to use Ruby the Ruby way, even for such functionality.

For example, if I have an array a, and want to create an array of square roots from it, currently I have to write:

a.map { |n| Math.sqrt n }

With this proposal, it would be possible to write:

a.map(&:sqrt)

This expresses the intent (map the squareroot function) in a much more concise and functional way.

If we introduce Numeric#sqrt, we should expand its domain to negative numbers and Complex numbers. Also, it is better to consider other kinds of numbers, such as Quaternion.

Now that Complex is built-in, producing an error on Math.sqrt(-2) indeed doesn't look good. That's independent of this proposal, but it could be implemented together.

Updated by Hanmac (Hans Mackowiak) over 2 years ago

For the Complex Problem, maybe add an optional parameter like :raise_on_complex or something so when you try:

(-2).sqrt it returns complex,
but (-2).sqrt(raise_on_complex: true) makes the old Exception?

Updated by Eregon (Benoit Daloze) over 2 years ago

Out of all Math methods:

  acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, cos, cosh, erf,
  erfc, exp, frexp, gamma, hypot, ldexp, lgamma, log, log10, log2, sin,
  sinh, sqrt, tan, tanh

I think for me only sqrt would maybe feel natural as num.sqrt.

We already have Integer.sqrt (but no #sqrt), so that might be confusing.
Math always deals with Float numbers, so that's consistent, but having it on numeric is less clear, should 5.sqrt be 2 (like Integer.sqrt) or 2.23606797749979 (like Math.sqrt)?
It's also not clear what should be Rational(a, b).sqrt, a Float, a Rational? The point of Rational is to be exact, converting to Float somewhat implicitly doesn't seem good.

At least I feel num.sin, num.cos, num.acos, num.cosh, etc, all look weird.
I would think many people would generally agree to that, but maybe I'm wrong.

Math.hypot seems also a good example why that should not be an instance method, because it takes two arguments as equal, there is no "receiver" and "operand" distinction.


Moving these methods to Float (instead of Numeric) would at least make it clear they use Float operands and return a Float, and sounds like a better change to me.
That would mean integer.to_f.sqrt if one wants the Float square root of an integer.

It seems Rust defines most of the Ruby Math methods on f64 (https://doc.rust-lang.org/std/primitive.f64.html) and much less (e.g., no sqrt) on i64 (https://doc.rust-lang.org/std/primitive.i64.html).

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0