I want to use arrow notation in Ruby

Allows you to calculate exponentiation with ↑

The operators of the four arithmetic operations are common to most programming languages, + -`` * ``/, but the exponentiation operator varies depending on the programming language. In Ruby and Python, it is **, but in BASIC it is ^, and in the first place, there are many languages ​​such as C and JavaScript before ES2016 that do not have a power operator.

reference:Exponentiation operator|Numeric type|Programming language comparison|hydrocul notes

By the way, in some areas, exponentiation is represented by "↑". That is $ 2 \ uparrow 4 = 2 ^ 4 = 16 $. So let's make it possible to calculate exponentiation with "↑" even in Ruby.

Unfortunately, no matter how flexible Ruby is as a programming language, you can't create new operators yourself. [^ 1] So, please forgive the point where you want to write "2 ↑ 4" with a dot like 2. ↑ 4.

[^ 1]: I can't ... right? Please comment if there is a way.

class Integer
  def ↑(n)
    self ** n

puts 2.↑ 4 # => 16 (2 to the 4th power)

You can do this because Ruby can also use non-ASCII characters in method names. [^ 2]

[^ 2]: It is good manners to use Refinement when extending a built-in class like this, but since the method_missing that will be used later cannot be used in Refinement, it directly extends Integer.

In Ruby 3.0, you can also use the endless method definition to write:

  def ↑(n) = self ** n

↑↑ Tetration

By the way, exponentiation was a repetition of multiplication.

2 \uparrow 4 = 2^4 = \underbrace{2 \times 2 \times 2 \times 2}_{4 2}

Then, you will want to think about the operation of "repetition of exponentiation". In some neighborhoods, it is called "tetration" and is represented by "↑↑".

2 \uparrow\uparrow 4 = \underbrace{2 \uparrow 2 \uparrow 2 \uparrow 2}_{4 2} = 2^{2^{2^2}} = 2^{2^4} = 2^{16} = 65536

So I would like to be able to calculate the titration with 2. ↑↑ 4. If that's the only purpose, you can write it like this.

  def ↑↑(n)
    Array.new(n, self).inject{ |result, item| item.↑ result }

I'd like to write Array.new (n, self) .inject (: ↑), but this doesn't work. Since power is right-associative, it should be $ 3 \ uparrow 3 \ uparrow 3 = 3 \ uparrow (3 \ uparrow 3) = 3 \ uparrow 27 = 7625597484987 $, but Array.new (n, self) .inject ( : ↑) If it is, it means $ (3 \ uparrow 3) \ uparrow 3 = 27 \ uparrow 3 = 19683 $ in the calculation order.

Beyond Tetration

Now, we have defined an operation called titration that repeats exponentiation. Then you want to define the operation of repeating tetration. It is called "pentation" and is represented by "↑↑↑". In other words

2 \uparrow\uparrow\uparrow 4 = \underbrace{2 \uparrow\uparrow 2 \uparrow\uparrow 2 \uparrow\uparrow 2}_{4 2}

It is that.

If you're writing a program that just does pentation, copy and paste the code above and tweak it a bit

  def ↑↑↑(n)
    Array.new(n, self).inject{ |result, item| item.↑↑ result }

It would be good.

However, as you can imagine, there is a "↑↑↑↑" (hexation) beyond the pentation. Furthermore, you can extend the arrow infinitely with "↑↑↑↑↑", "↑↑↑↑↑↑" ...

It is possible to define the operation one level higher by copying and pasting with the above method, but it is really troublesome to define up to "↑↑… (100 ↑)… ↑↑". A possible method in such cases is dynamic method definition using define_method.

class Integer
  2.upto(100) do |i|
    define_method("↑" * i) do |n|
      operator = "↑" * (i - 1)
      Array.new(n, self).inject{ |result, item| item.send(operator, result) }

This way, you can easily define from "↑↑" to "↑↑ ... (100 ↑) ... ↑↑".

However, after defining the methods up to "↑↑… (100 ↑)… ↑↑" in this way, there may be an opportunity to need “↑↑… (101 ↑)… ↑↑”. [^ 3] No matter how many "↑↑… ↑↑" are needed, I want to be able to handle them without rewriting the program.

[^ 3]: Probably not.

That's where the Ruby black art royal road method_missing comes into play. [^ 4]

[^ 4]: As you can see in the Official Documentation, when defining method_missing, also definerespond_to_missing?.

class Integer
  def ↑(n)
    self ** n

  def method_missing(name, *args)
    return super if name.match?(/[^↑]/)
    unless args.size == 1
      raise ArgumentError,
            "wrong number of arguments (given #{args.size}, expected 1)"

    operator = name[0..-2]
    n = args[0]
    Array.new(n, self).inject do |result, item|
      item.send(operator, result)

  def respond_to_missing?(symbol, include_private)
    symbol.match?(/[^↑]/) ? super : true

With this, we can handle whether it is titration, pentation, hexation, or "↑↑ ... (1000 ↑) ... ↑↑"!

Then, let's start by calculating lightly with 3 ↑↑↑ 3!

> puts 3.↑↑↑ 3

bignum too big to convert into `long' (RangeError)


[^ 5]: This number is called Toritori, and even if the particles of the entire universe are used as memory, it is a number that can never be expressed. Reference: Kamen Rider Build Formula Episode 16 Tetration

Write a program to find Graham's number

Now that we have defined the arrow notation, let's write a program to find the Graham's number, which is famous as a huge number in Guinness. Of course, it is a larger number than 3 ↑↑↑ 3, so it cannot be actually calculated, but it is possible if the calculation procedure is simply expressed as a program.

First, define a function $ g (n) = 3 \ underbrace {\ uparrow \ uparrow \ cdots \ uparrow \ uparrow} _ {n \ uparrow} 3 $, commonly called the Graham function.

def g(n)
  3.send("↑" * n, 3)

By defining the arrow notation using method_missing, the Graham function can be easily expressed in this way.

Graham's number is expressed using the Graham function as $ G = \ underbrace {g (g (\ cdots g (g (4)) \ cdots))} _ {64 g ()} $. The composition of the same function may be written as $ g ^ {64} (4) $ as a power.

If so, shouldn't we be able to write the composition of the same function in Ruby using the exponentiation operator ** as in method ** 64?

class Method
  def **(times)
    Array.new(times, self).inject(:>>)

Now the program for Graham's number is ready.

g64 = method(:g) ** 64
puts g64.call(4)

I was able to write a program to find Graham's number very simply!


I think the flexibility of Ruby goes well with mathematics, so if you are a mathematician, why not try using Ruby?

Recommended Posts

I want to use arrow notation in Ruby
I want to use @Autowired in Servlet
I want to get the value in Ruby
I want to use Combine in UIKit as well.
I want to use Clojure's convenient functions in Kotlin
I want to use fish shell in Laradock too! !!
I want to use ES2015 in Java too! → (´ ・ ω ・ `)
I want to use a little icon in Rails
I want to use FormObject well
I want to perform high-speed prime factorization in Ruby (ABC177E)
I want to create a Parquet file even in Ruby
I want to use DBViewer with Eclipse 2018-12! !!
[Ruby] I want to put an array in a variable. I want to convert to an array
I want to change the value of Attribute in Selenium of Ruby
[Ruby] I want to output only the odd-numbered characters in the character string
I want to sort by tab delimited by ruby
I want to send an email in Java.
[Ruby] I want to do a method jump!
I want to use java8 forEach with index
I want to pass APP_HOME to logback in Gradle
rsync4j --I want to touch rsync in Java.
[Ruby] I want to display posted items in order of newest date
[Xcode] I want to manage images in folders
I want to be eventually even in kotlin
I tried to make full use of the CPU core in Ruby
[Java Spring MVC] I want to use DI in my own class
I get an error when I try to use "^" or "$" in ruby ​​regular expression
[Ruby] How to use standard output in conditional branching
I want to do something like "cls" in Java
I want to use NetBeans on Mac → I can use it!
I want to embed any TraceId in the log
I want to define a function in Rails Console
[Android Studio] I want to use Maven library on Android
I want to stop snake case in table definition
I want to click a GoogleMap pin in RSpec
I want to convert characters ...
How to use Ruby return
Use ruby variables in javascript.
Rbenv command to use Ruby
Ruby: How to use cookies
I want to use PowerMock in a class that combines parameterized tests and ordinary tests
[Beginner] I want to modify the migration file-How to use rollback-
I want to find a relative path in a situation using Path
I want to set the conditions to be displayed in collection_check_boxes
I want to use the Java 8 DateTime API slowly (now)
What I did in the version upgrade from Ruby 2.5.2 to 2.7.1
I want to use the sanitize method other than View.
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I want to transition to the same screen in the saved state
I want to use FireBase to display a timeline like Twitter
[Ruby] I want to reverse the order of the hash table
I want to simplify the conditional if-else statement in Java
[Ruby on Rails] I want to get the URL of the image saved in Active Storage
Swift: I want to chain arrays
How to use Lombok in Spring
How to iterate infinitely in Ruby
Try to implement Yubaba in Ruby
How to use Ruby on Rails
I want to convert InputStream to String
How to install Bootstrap in Ruby
[Ruby] How to use any? Method