Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

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]

次に、これらのクラスを表形式で見てみましょう。

クラス 説明 整数 修正 大きな数字に使用 フロート 不正確な10進数 複雑 虚数の数学に使用されます 合理的 分数を表すために使用されます 完璧な精度の10進数
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 は単なる通常のオブジェクトです。

この投稿がおもしろいと思ったら、下のフォームで私のニュースレターにサインアップすることを忘れないでください🙂


  1. Ruby 2.6のMJITとは何ですか?どのように機能しますか?

    Rubyのパフォーマンスはバージョンごとに大幅に向上しており、Ruby開発チームはRubyをさらに高速化するためにあらゆる努力をしています! これらの取り組みの1つは、3×3プロジェクトです。 目標は? Ruby3.0はRuby2.0の3倍高速になります 。 このプロジェクトの一部は、この記事のトピックである新しいMJITコンパイラです。 MJITの説明 MJITは「メソッドベースのジャストインタイムコンパイラ」の略です。 それはどういう意味ですか? RubyはコードをYARV命令にコンパイルします 、これらの命令はRuby仮想マシンによって実行されます。 JITはこれに別のレ

  2. Rubyの配列クラスの使用方法(例+便利なメソッド)

    アレイとは何ですか? 配列は組み込みのRubyクラスであり、0個以上のアイテムのリストを保持します 、およびこれらすべてのアイテムを簡単に追加、アクセス、およびループするのに役立つメソッドが含まれています。 配列が存在しない場合は多くの変数を使用する必要があるため、これは便利です。 例 : a =1b =2c =3 しかし、代わりに、あなたはそうすることができます : 番号=[1、2、3] 最良の部分は? 配列内には何でも入れることができます! いいね : 数字 文字列 より多くのアレイ! (それは多次元配列になります) アレイを最大限に活用できるように、アレイについ