Ruby中全部數值都是Numeric類的子類對象,數值都是不可變對象。html
數值類型的繼承關係以下:ruby
Integer是整數,Float是浮點數類型,Rational是分數。測試
對於整數,要麼是Fixnum,要麼是Bignum:Fixnum是比較小整數的類型(31個二進制位),Bignum是較大整數的類型。實際上,Ruby中的整數能夠變得任意大。可是浮點數不會任意大,浮點數位數達到一點程度後會溢出到正、負無窮。ui
Fixnum和Bignum之間在須要的時候會自動轉換:當一個初始爲Bignum類型的變量值變小後,會自動轉換成Fixnum類型;同理,Fixnum的變量也會在它變得足夠大時轉換成Bignum類型。3d
對於分數,只須要在某個數後面加上一個後綴字母r
,就會自動轉換爲分數形式。例如0.3r
等價於分數(3/10)
,2r
等價於2/1r
等價於分數形式(2/1)
。在Kernel模塊中有一個Rational方法,能夠用來將各類類型轉換成分數形式。code
當算術運算的兩個操做數中,有一個是Float類型,那麼整數類型將轉換成Float類型進行運算,運算結果也都是Float類型。htm
>> 2 * 2.5 => 5.0 >> 1.0 + 2 => 3.0 >> 5.0/2.5 => 2.0 >> 5.0/2 => 2.5
對於整數除法,即兩個數都是整數的除法,那麼除法獲得的結果將是截斷後的整數。對於結果爲負數的整數除法,將取比它精確結果更小的整數。也就是說,Ruby中的整數除法採起的是地板除法(floor)因此,(-a)/b
等價於a/(-b)
,可是可能不等價於-(a/b)
。對象
>> 5/2 => 2 >> -3/2 # (-a)/b => -2 >> 3/-2 # a/(-b) => -2 >> -(3/2) # -(a/b) => -1
浮點數是不精確的,因此不要在浮點數參與運算的時候對浮點數作等值比較。非要比較,能夠經過減法運算,跟一個足夠小的值作大小比較,但也別小過頭了。例如,(0.4-0.1)
和0.3作等值比較:blog
>> (0.4 - 0.1) == 0.3 => false >> 0.4 - 0.1 => 0.30000000000000004 >> ( 0.4 - 0.1 ) - 0.3 < 0.00001 # 這是正確的浮點數參與運算的等值比較方式 => true >> ( 0.4 - 0.1 ) - 0.3 < 0.0000000000000000000001 => false
可使用Rational分數來比較:繼承
>> (0.4r-0.1r) == 0.3r #=> true >> 0.4r #=> (2/5) >> 0.1r #=> (1/10) >> 0.4r-0.1r #=> (3/10) >> 0.3r #=> (3/10)
也可使用BigDecimal類來進行運算,它採用的是十進制表示法來表示浮點數,而Float採用的是二進制表示法表示。只不過BigDecimal的運算速度要比正常的浮點數速度慢上不少個數量級,固然,對於普通的財務運算等領域也足夠了,只是在進行科學運算的時候,BigDecimal就不夠了。另外,BigDecimal不是內置類,只是一個標準庫,須要先導入。
require "bigdecimal" (BigDecimal("0.4") - BigDecimal("0.1")) == BigDecimal("0.3") #=> true
如下是幾種浮點數運算等值比較的效率高低(比較100W次):
# 直接使用浮點數比較,比較是不精確的 $ time ruby -e '1000000.times {|x| (0.4-0.1) == 0.3 }' real 0m0.147s user 0m0.063s sys 0m0.078s # 直接使用浮點數作不等值比較,比較是精確的 # (屢次測試,速度比上面要慢一點點,多了次運算) $ time ruby -e '1000000.times {|x| (0.4-0.1) - 0.3 < 0.00001 }' real 0m0.158s user 0m0.094s sys 0m0.063s # 使用分數字面量,比較是精確的 $ time ruby -e '1000000.times {|x| (0.4r-0.1r) == 0.3r }' real 0m0.248s user 0m0.188s sys 0m0.094s # 使用Kernel中的Rational() $ time ruby -e '1000000.times {|x| (Rational("0.4") - Rational("0.1")) == Rational("0.3") }' real 0m0.630s user 0m0.563s sys 0m0.063s # 使用bigdecimal $ time ruby -r"bigdecimal" -e '1000000.times do |x| (BigDecimal("0.4") - BigDecimal("0.1")) == BigDecimal("0.3") end' real 0m1.079s user 0m0.953s sys 0m0.125s
可見,使用分數字面量或浮點數不等值比較的效率是比較可取的,而使用Kernel.Rational()或BigDecimal()的效率相比之下都比較差。
對於Ruby中的取模%
運算,也是支持浮點數的。
>> 1.5 % 0.4 => 0.29999999999999993
指數運算時,採起的是Fortran裏的優先級模式,和Perl是同樣的:從右向左計算。例如3 ** 4 ** 2
等價於3 ** (4 ** 2)
,即其值爲3 ** 16
:
>> 3 ** 4 ** 2 => 43046721 >> 3 ** 16 => 43046721
指數運算的指數支持浮點數、負數,只是指數涉及到整數除法運算時須要注意,由於對於整數除法,Ruby默認採用的是floor除法:
x ** 4 x ** -1 # 即x分之1 x ** (1/3.0) # 即x的立方根 x ** (1/4) # 1/4=0,等價於x ** 0,即結果爲1 x**(1.0/4.0) # 即x的四次方根
雖然,數值是不可變對象,可是對於整數來講,它支持索引查找各個二進制位上的值,只是不容許修改。
>> printf "%b\n", 12345 11000000111001 # 這是十進制12345對應的二進制數 >> x[0] => 1 >> x[1] => 0 >> x[4] => 1 >> x[5] => 1 >> x[6] => 0 >> x[11] => 0 >> x[12] => 1
因此,要判斷一個數是否爲偶數,就很是容易了:
x[0] == 0 # 偶數返回true,奇數返回false