Rubyで数値がどのように機能するか:整数、浮動小数点数、およびBigdecimalを理解する
Ruby2.4はFixnum
をマージしました &Bignum
同じクラスに(Integer
)ですから、Rubyのさまざまな数値タイプを確認する良い機会だと思います!
それがこの投稿で話し合うことです🙂
数値タイプの概要
まず、Rubyのすべての関連クラスのクラス階層を見てみましょう。
Numeric Integer Fixnum Bignum Float Complex Rational BigDecimal (Standard Library)
ご覧のとおり、Numeric
classは、すべての数値クラスの親です。 ancestors
を使用できることを忘れないでください 任意のクラスの親クラスを検出するメソッド。
例 :
Fixnum.ancestors - Fixnum.included_modules [Fixnum, Integer, Numeric, Object, BasicObject]
次に、これらのクラスを表形式で見てみましょう。
Fixnum の親クラス &Bignum | 1 |
OS整数型(32ビットまたは64ビット)に適合する整数 | 1 |
Bignum | 111111111111 |
5.0 | |
(1 + 0i) | |
(2/3) | |
BigDecimal | 3.0 |
フロートの不正確さ
Float
Rubyのクラスは、Rubyの公式ドキュメントでは「不正確」と説明されています。
なぜですか?
例を示しましょう :
0.2 + 0.1 == 0.3 # false
なぜこれが間違っているのですか?
0.2 + 0.1
の結果を見てみましょう :
0.30000000000000004
丁度!それが不正確さの意味です。
これは、フロートの保存方法が原因で発生します。常に正確な10進数が必要な場合は、BigDecimal
を使用できます。 クラス。
フロートとBigDecimal
BigDecimalは、任意精度の10進数を提供するクラスです。
例 :
require 'bigdecimal' BigDecimal("0.2") + BigDecimal("0.1") == 0.3 # true
いつもBigDecimal
を使ってみませんか それから?かなり遅いからです!
ここにベンチマークがあります :
Calculating ------------------------------------- bigdecimal 21.559k i/100ms float 79.336k i/100ms ------------------------------------------------- bigdecimal 311.721k (± 7.4%) i/s - 1.552M float 3.817M (±11.7%) i/s - 18.803M Comparison: float: 3817207.2 i/s bigdecimal: 311721.2 i/s - 12.25x slower
BigDecimal
Float
より12倍遅い 、それがデフォルトではない理由です🙂
Fixnum vs Bignum
このセクションでは、Fixnum
の違いについて説明します。 およびBignum
Ruby2.4より前。
コードから始めましょう :
1.class # Fixnum 100000000000.class # Bignum
Rubyは私たちのために正しいクラスを作成し、それは自動的にFixnum
をプロモートします Bignum
に 必要に応じて。
注 :
Bignum
を取得するには、より大きな数値が必要になる場合があります 64ビットのRubyインタープリターがある場合はオブジェクト。
なぜ異なるクラスが必要なのですか?答えは、大きな数値を処理するには別の実装が必要であり、大きな数値を処理するのは遅いため、Float
と同様の状況になるということです。 vs BigDecimal
。
Fixnumの特別な属性
Fixnum
クラスにはいくつかの特別なプロパティもあります。たとえば、オブジェクトIDは式を使用して計算されます。
1.object_id # 3 20.object_id # 41
式は次のとおりです。(number * 2) + 1
。
ただし、Fixnum
を使用する場合は、これだけではありません。 作成されているオブジェクトはまったくありません。 Fixnum
に保存するデータはありません 、値はオブジェクトID自体から派生しているためです。
これは単なる実装の詳細ですが、知っておくと面白いと思います🙂
MRI(MatzのRuby Interpreter)は、次の2つのマクロを使用して、値とオブジェクトIDを変換します。
INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG)) FIX2LONG(x) ((long)RSHIFT((SIGNED_VALUE)(x),1))>
ここで起こることは「ビットシフト」と呼ばれ、すべてのビットを左または右に移動します。
1つの位置を左にシフトすることは、2を掛けることと同じです。そのため、数式は(number * 2) + 1
になります。 。 +1はFIXNUM_FLAG
から取得されます 。
対照的に、Bignum
通常のクラスのように機能し、通常のオブジェクトIDを使用します:
111111111111111.object_id # 23885808
つまり、Fixnum
Bignum
の場合、オブジェクトはインタープリターレベルでどのように機能するかという点でシンボルに近いです。 オブジェクトは文字列に近いです。
2.4の整数
Ruby 2.4 FixnumとBignumは非推奨ですが、舞台裏では同じように機能します。
Rubyはあるタイプから別のタイプに自動的に切り替わります。
クラスを変更せずに 。
これは、小さなInteger
を意味します 数値は引き続きFixnum
と同じように機能します 。
概要
この投稿では、Rubyに存在するさまざまな数関連のクラスについて学びました。
フロートが不正確であり、BigDecimal
を使用できることを学びました 精度がパフォーマンスよりもはるかに重要である場合。また、Fixnum
オブジェクトはインタプリタレベルでは特別ですが、Bignum
は単なる通常のオブジェクトです。
この投稿がおもしろいと思ったら、下のフォームで私のニュースレターにサインアップすることを忘れないでください🙂
-
Ruby 2.6のMJITとは何ですか?どのように機能しますか?
Rubyのパフォーマンスはバージョンごとに大幅に向上しており、Ruby開発チームはRubyをさらに高速化するためにあらゆる努力をしています! これらの取り組みの1つは、3×3プロジェクトです。 目標は? Ruby3.0はRuby2.0の3倍高速になります 。 このプロジェクトの一部は、この記事のトピックである新しいMJITコンパイラです。 MJITの説明 MJITは「メソッドベースのジャストインタイムコンパイラ」の略です。 それはどういう意味ですか? RubyはコードをYARV命令にコンパイルします 、これらの命令はRuby仮想マシンによって実行されます。 JITはこれに別のレ
-
Rubyの配列クラスの使用方法(例+便利なメソッド)
アレイとは何ですか? 配列は組み込みのRubyクラスであり、0個以上のアイテムのリストを保持します 、およびこれらすべてのアイテムを簡単に追加、アクセス、およびループするのに役立つメソッドが含まれています。 配列が存在しない場合は多くの変数を使用する必要があるため、これは便利です。 例 : a =1b =2c =3 しかし、代わりに、あなたはそうすることができます : 番号=[1、2、3] 最良の部分は? 配列内には何でも入れることができます! いいね : 数字 文字列 より多くのアレイ! (それは多次元配列になります) アレイを最大限に活用できるように、アレイについ