Project

General

Profile

Actions

Feature #20404

closed

`2pi`

Added by mame (Yusuke Endoh) 8 months ago. Updated 8 months ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:117390]

Description

I propose a new Float literal: 2pi.

p 2pi  #=> 6.283185307179586 == 2 * Math::PI

I am not proposing 1pi, 3pi or 4pi. I do only 2pi. Because in most cases, all you need is 2pi. Any other multiple of pi is rarely needed.

I've got the statistics. GitHub code search revealed that more than 80% of the occurrences of n * Math::PI and Math::PI * n had n = 2. [1]

n n * Math::PI Math::PI * n sum %
0 48 1 49 1.4%
1 58 3 61 1.7%
2 2300 534 2834 80.4%
3 218 17 235 6.7%
4 200 23 223 6.3%
5 24 2 26 0.7%
6 41 3 44 1.2%
7 14 0 14 0.4%
8 6 2 8 0.2%
9 8 0 8 0.2%
10 17 0 17 0.5%
11 2 0 2 0.1%
12 2 0 2 0.1%

Here is the PIe chart

I know that a new constant name "Tau" is proposed (#4897, #17496). But notice: "2pi" and "Tau" have the same number of characters. Then, it is obvious that familiarity is better. In fact, 2 * Math::PI is 4 times more than Math::PI * 2, indicating that all programmers are copying "2pi" in their textbook.

The idea of 2pi came up regularly in chats among committers. The discussion quickly shifted to its generalization: should we treat 3e as 3 * Math::E, or even 42foo as 42 * foo? However, I noticed such a generalization is unnecessary because all we need is 2pi. Unneeded generalization is evil.

Here is a patch.

diff --git a/parse.y b/parse.y
index 55619273b8..93b16a16ac 100644
--- a/parse.y
+++ b/parse.y
@@ -10208,6 +10208,13 @@ parse_numeric(struct parser_params *p, int c)
             return set_number_literal(p, tINTEGER, suffix, 10, 0);
         }
     }
+    else if (c == '2' && peek(p, 'p') && peek_n(p, 'i', 1)) {
+        tokadd(p, c);
+        tokadd(p, nextc(p));
+        tokadd(p, nextc(p));
+        tokfix(p);
+        return set_number_literal(p, tFLOAT, 0, 0, 0);
+    }

     for (;;) {
         switch (c) {
diff --git a/ruby_parser.c b/ruby_parser.c
index 6d85a72c5b..3a6e0b5704 100644
--- a/ruby_parser.c
+++ b/ruby_parser.c
@@ -936,6 +936,9 @@ VALUE
 rb_node_float_literal_val(const NODE *n)
 {
     const rb_node_float_t *node = RNODE_FLOAT(n);
+    if (strcmp(node->val, "2pi") == 0) {
+        return DBL2NUM(2 * M_PI);
+    }
     double d = strtod(node->val, 0);
     if (node->minus) {
         d = -d;

       P I  
Happy a r l fool

[1] I used these queries: /[^.]\b2 ?\* ?Math::PI/ language:Ruby and /Math::PI *\* *2\b *[^.\/]/ language:Ruby


Related issues 1 (1 open0 closed)

Related to Ruby master - Feature #17496: Add constant Math::TAUOpenActions

Updated by duerst (Martin Dürst) 8 months ago

I really like this proposal. But I think for most of the world, it was a few hours too early. A time around 2024-04-01 12:00:00 UTC may have been easier to understand for most of the world.

Updated by byroot (Jean Boussier) 8 months ago

Now that Ruby has been unicode aware for over a decade, it's probably better to use actual pi letter:

Updated by shan (Shannon Skipper) 8 months ago

The Tau Manifesto (https://tauday.com/) was introduced by Michael Hartl, a Rubyist, and handily 𝜏 == 2π so it might be worth also considering the tau letter: 𝜏

Updated by jzakiya (Jabari Zakiya) 8 months ago

This has been brought up before to add the constant tau

https://bugs.ruby-lang.org/issues/17496

Actions #5

Updated by hsbt (Hiroshi SHIBATA) 8 months ago

Updated by mame (Yusuke Endoh) 8 months ago

  • Status changed from Open to Rejected

April Fools' Day is over. Closing.

This proposal is half joke, half serious. I can think of some reasons why we should introduce 2pi.

There are some languages that provide not only pi but also commonly used values.

@ko1 (Koichi Sasada) and @shyouhei (Shyouhei Urabe) told me that Gauche and C (POSIX) defines the following constants. It seem reasonable to provide frequently used values, even if they can be easily computed from other values.

  • Gauche (Scheme): pi, 2pi, pi/2, pi/4, pi/180, 1/pi, and 180/pi
  • C (POSIX): pi, pi/2, pi/4, 1/pi, 2/pi, and 2/sqrt(pi) (but not 2pi, why?)

https://practical-scheme.net/gauche/man/gauche-refe/Mathematical-constants.html
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/math.h.html

There is no good alternative constant name.

We cannot define Math::2PI unfortunately. Math::PI2 and Math::PI_2 are in unnatural word order, and also ambiguous as pi^2 or pi/2. Math::TWO_PI does not look so good.
I mentioned Tau in the original proposal, and seriously, I don't believe that Math::Tau is the way to go at the present. As long as most textbooks use 2pi, programmers will have to replace it with 2pi in their mind every time they see Math::Tau, which is too inconvenient. We should consider this when most textbooks start using Tau. (If I had a time machine, I would try to convince the ancient Greeks to consider the ratio of circumference to radius instead of diameter.)

Math::PI is often the only used one in Math module.

Because Ruby has Complex, it is often not necessary to use Math.sin and cos directly. When dealing with 2D graphics, we typically use only Complex multiplication and Math::PI.

Math::PI leads to a bit cryptic code.

For example, to find the coordinates of the vertices of a hexagon, one would write Complex.polar(1, 2 * Math::PI / 6 * n). However, many people may be bothered by the redundant multiplication and rewrite it as Complex.polar(1, Math::PI / 3 * n). Then the original intent of the hexagon disappears from the code. Since math code tends to be originally cryptic, I think it is better if the intent remains as straightforward as possible. With 2pi, we could write Complex.polar(1, 2pi / 6 * n).

... Well, but I wonder if a new literal is impossible?

Updated by zverok (Victor Shepelev) 8 months ago

This proposal is half joke, half serious.

There are several interesting things to unpack here (though I don’t see any actionable proposals). When writing/reading in Ruby some math, there are several different irky things:

  1. Math:: prefix (honestly, I never felt it totally justified, like sin or cos is obvious without any prefixes, why should we have it?..)—but at least can be mitigated by include Math
  2. PI in all-caps. I understand it corresponds to the constant rules of Ruby, yet in a complicated formula, it really catches your eye as ”something I’d like to read in a less screaming manner” (in some cases, I even introduced a local variable π to write some cumbersome formula)
  3. The math intuition of 2<variable> to mean 2 * <variable>, and in some formulae, perceived as an atomic part of it

(3) in some languages (can’t remember which ones from the top of my head, but I definitely saw it) is addressed by treating <number><identifier> as <number> * <identifier>. IDK, maybe this is the way?.. Currently, 2x is a syntax error, so there should be no conflicts.

And also... Can it be possible to introduce Math::pi and Math::e (which, by the logic of naming, should be methods, yet maybe can be treated by parser or optimizer as constants)?..

Just thoughts.

Updated by duerst (Martin Dürst) 8 months ago

zverok (Victor Shepelev) wrote in #note-7:

When writing/reading in Ruby some math, there are several different irky things:

One thing that irks me about Math::sin and friends is that these are not available as methods (on Float and so on). It's annoying, and doesn't feel like Ruby, to have to write array.map { |x| Math.sin x } instead of just array.map(&:sin). I understand why in some places, you want sin in prefix position so that it looks like it does in a Mathematical formula, but in Ruby, there are often multiple ways to write things, so it shoulsd also be possible to write x.sin.

Updated by nobu (Nobuyoshi Nakada) 8 months ago

zverok (Victor Shepelev) wrote in #note-7:

(3) in some languages (can’t remember which ones from the top of my head, but I definitely saw it) is addressed by treating <number><identifier> as <number> * <identifier>. IDK, maybe this is the way?.. Currently, 2x is a syntax error, so there should be no conflicts.

Already we have 2i, 2r and 2ri.

Actions

Also available in: Atom PDF

Like3
Like0Like0Like0Like0Like0Like0Like0Like0Like0