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