1. 程式人生 > Ruby 程式語言入門 >07 Ruby 數字物件

07 Ruby 數字物件

人們所熟知的數字型別有整數、小數、分數等等,今天讓我們學習在 Ruby 中學習數字物件,瞭解在 Ruby 中數字是如何進行運算的。

1. 為什麼要使用數字物件

自然界的每個事物,我們通常根據其特徵將數字分為不同的集合,開發的時候我們一共能接觸到的數字按照特徵可以分為自然數、整數、有理數、無理數。為了能讓我們對數字進行我們熟知的運算操作(例如:加減乘除),Ruby 使用了數字物件。

2. Ruby 中數字物件

在不同的程式語言中擁有各式各樣的數字型別。在 Ruby 中我們將數字物件分為整型(Integer)有理數(Rational)浮點數(Float)小數(BigDecimal)四種。

2.1 整型(Integer

自然數是指從1開始按順序加1的自然數。例如:1、2、3、4、5…。整數是相同的數字,但也包含與此對應的負數以及0,即0,-1,-2,-3,-4,…。Ruby對此集合有一個表示形式:抽象類 Integer

注意事項:在 Ruby2.4 版本之前,Integer 有 FixnumBignum 兩個子類,他們所處理的數字大小範圍不同。

Fixnum 的範圍是在 -2^62 ~ 2^62-1 之間,超出範圍則自動變為 Bignum。

例項:

# Ruby2.4之前
# 以下 > 均代表irb的輸入模式
# => 後面是返回值
> integer = 2 ** 62 - 1
=
> 4611686018427387903 > integer.class => Fixnum > integer = (integer + 1).class => Bignum > (-integer - 2).class => Bignum

解釋:當前程式碼執行環境是在 Ruby 2.2.4,我們可以看到 2^62-1 所表示的整數類是 Fixnum,當把 integer 增加 1 後,類名變成了 Bignum。

Ruby 2.4及以後不會使用 FixnumBignum,但是內部它們仍然以相同的方式工作,Ruby 會自動從一種型別切換到另一種型別。意思是較小的 Integer 數字仍然以與 Fixnum 相同的方式執行。

# Ruby2.4及之後的版本
> integer = 2 ** 62 - 1
=> 4611686018427387903
> integer.class
=> Integer
> integer = (integer + 1).class
=> Integer
> (-integer - 2).class
=> Integer

為了能讓 Integer 更好地被讀取,您可以在數字之間增加下劃線,比如 188_000 就會比 188000 更好讀懂。

例項:

> 188_000
=> 188000

對於常見的基本的運算您需要注意除法,當除數與被除數均為 Integer 的時候,返回的結果仍然是 Integer,小數點及後面的值會被省略。

例項:

> 1000000/6
=> 166666

2.2 有理數(Rational

在現實中,我們不能用整數代表一切。比如整數 1 除以 2,您可以用兩種方式檢視結果,一種是 1/2,另一種是 0.5。而這種類似比率或除法的表現形式,被稱作 有理數(Rational)

下面是有理數的建立形式:

例項:

> Rational(1, 2) # 第一個數為分子,第二個數為分母
=> (1/2)

除此之外您還可以使用硬編碼的模式:使用十進位制的數字並在後面加上r

例項:

> 0.5r
=> (1/2)

當有理數之間或者有理數與整數進行運算的時候,得到的結果都是有理數型別。

例項:

> rational = Rational(1, 2) + Rational(1, 2)
=> (1/1)
> rational.class # 檢視這個變數的類
=> Rational
> rational.to_i # to_i意思為轉換成Integer
=> 1

Tips : 如果您對獲取結果的可讀性和精度有極高的要求,而且整型不滿足結果的需求,請使用有理數,

2.3 浮點數(Float

不是所有的數字都可以使用比例的方式來表示,比如 π 。為了在 Ruby 中表示 無理數(Irrationals),我們使用了浮點數(Float)

下面舉一個 π 的例子,我們使用 Math::PI 來獲取π。

例項:

> Math::PI
=> 3.141592653589793
> Math::PI.class
Float

我們在 Ruby 中所定義的帶小數點的數字也都是浮點數。

> 1.2.class
=> Float
> 0.00001.class
=> Float

Tips:浮點數在 Ruby 中是不精確的

例項:

> 0.2 + 0.1 == 0.3
=> false
> 0.2 + 0.1
=> 0.30000000000000004
> (0.2 + 0.1 + 0.7) == 1.0
=> true

您會發現在浮點數的運算中,2.0 - 1.1和0.9並不相等,發生這種情況是因為1985年由IEEE定義的標準(以及 Ruby在其內部使用的標準)以有限的精度儲存數字(這個可以不深究)。如果需要始終正確的十進位制數,則需要使用小數(BigDecimal)

當 Float 的結果非常大超出了其精度範圍,我們使用 Infinity

例項:

> 500.0e1000 # 500.0的1000次方
=> Infinity

超出範圍的計算也是同樣的結果,比如除數為 0 的情況。

例項:

> 1 / 0.0
=> Infinity
> -1 / 0.0
=> -Infinity

Tips:也可以直接使用Float::INFINITY來直接呼叫。

為了顯示非數字的結果,Ruby 引入了特殊值 NaN。

例項:

> 0 / 0.0
=> NaN
> Float::INFINITY / Float::INFINITY
=> NaN
> 0 * Float::INFINITY
=> NaN

2.4 小數(BigDecimal

在 Ruby 中 小數(BIgDecimal)可以為您提供一個任意精度的十進位制數字。

在使用小數前,我們要引入一個bigdecimal,定義小數的時候我們要使用一個字串String)(內容用雙引號或單引號括起來,在Ruby字串物件的章節中會詳細講到)。

> require 'bigdecimal'
=> true
> BigDecimal("0.2") + BigDecimal("0.1") == 0.3
=> true

解釋:為了能使用BigDecimal方法,要執行require 'bigdecimal'來引用這個庫。

經驗:在開發中對使用者設定餘額或者金融計算的時候,一定要使用小數,因為這種情況不允許我們出現小數點精度不準確的問題。

注意事項:我們建立 BigDecimal 的時候一定要使用字串作為引數,使用浮點數同樣會造成精度缺失的問題。

既然小數是準確的那為什麼 Ruby 預設的帶小數點的數字是Float型別呢?

答案是:Float會 比 BigDecimal 快很多,大約快了12 倍

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 為了精確地表達精度,將整數部分和小數部分分開運算,所以花費了很多時間。

3. 常見的數字物件的例項方法

數字物件是一個物件,它擁有很多例項方法,下面會講到一些常見的例項方法,如果是某個型別專用,我會使用括號標記出來。

3.1 基本數學運算

基本數學運算就是我們常見的加(+)減(-)乘(*)除(/)以及取餘(%)。

經驗:

  • 整型之間進行運算結果返回整型;

  • 如果有浮點數參與運算結果返回浮點數;

  • 整型的除法會返回商的整數部分。

例項:

1 + 1           # 2
1 + 1.0         # 2.0
10 / 4          # 2
10 / 4.0        # 2.5
10.0 / 4.0      # 2.5
10 % 3          # 1

3.2 值大小比較

常見的有等於(==)、不等於(!=)、大於(>)、小於(<)、大於等於(>=)、小於等於(<=)。

例項:

1 == 1.0  # true
2 > 1     # true
1 <= 0    # false

也可以對算數表示式結果進行判斷。

例項:

1 + 1 == 2  #true

注意事項:

因為浮點數不準確,不建議使用浮點數進行精確的比較。精確的比較請使用 小數(BigDecimal)

例項:

5.01 == 5.0 + 1.01  # false

3.3 判斷值與數字型別是否均相等

eql? 方法則可以判斷值和型別是否均相同。

例項:

1 == 1.0      # true
1.eql?(1.0)   # false 1是Integer,1.0是Float

3.4 奇偶性的判斷(整型)

odd?是奇數的判斷,even?是偶數的判斷。

3.odd?   # true
2.even?  # true

3.5 小數點位數保留

這裡我們有 3 個方法ceilfloorround

  • ceil返回不小於該數字的最大整數;

  • round返回該數字四捨五入後的整數;

  • floor返回不大於該數字的最大整數。

例項:

2.5.ceil   # 3
2.5.round  # 3
2.5.floor  # 2

我們也可以通過傳遞引數,來調整位數,預設引數為0,往小數點右邊為正,左邊為負。

例項:

2.555.ceil(1)   # 2.6
2.555.round(1)  # 2.6
2.555.floor(1)  # 2.5
2.555.ceil(-1)  # 10
2.555.round(-1) # 0
2.555.floor(-1) # 0

3.6 類別轉換

常用的有to_ito_fto_s

  • to_i轉換為整型;

  • to_f轉換為浮點型;

  • to_s轉換為字串。

例項:

1.0.to_i  # 1
1.to_f    # 1.0
1.0.to_s  # "1.0"

3.7 最大公因數(整型)

使用 gcd(),例如:求 10 和 5 的最大公因數。

例項:

10.gcd(5)  # 5

3.8 最小公倍數(整型)

使用 lcm(),例如:取 10 和 5 的最小公倍數。

例項:

10.lcm(5)  # 10

3.9 絕對值

使用 abs,例如:取 -1 和 1.0 的絕對值。

-1.abs   # 1
1.0.abs  # 1.0

3.10 冪

有兩種方式,第一種為**

2**10  # 1024

第二種為pow()

2.pow(10)

除此之外 pow 還可以傳遞第二個引數,意思為在取冪之後再求餘數。

2.pow(10, 100)  # 24,相當於 2**10 % 100

3.11 判斷是否為 0

使用zero?

例項:

0.zero? # true

4. 小結

本章節我們學習了整型、有理數、浮點數、小數,知道了浮點數在 Ruby 中是不準確的,而小數是準確的,瞭解了常用的數字物件例項方法,例如如何運算、比較、型別轉換等等。在實際專案中,我們會不斷使用到數字物件,一定要好好學習和總結。