1 处理复数

标准库complex 能使我们处理复数。一个复数的创建能使用Complex来构造:
require 'complex'

puts Complex(1,2)    # 3+5i


方法im能够转换一个数字为虚数:
puts a = 3.im       # 3i
puts b = 5 - 2.im   # 5-2i


如果你想表示极坐标的话,可以使用polar方法:

puts z = Complex.polar(5,Math::PI/2.0)  #第一个参数是半径,第二个参数是角度


Complex还提供了I这个常量,他就表示复数中的i:
puts z1 = Complex(3,5)
puts z2 = 3 + 5*Complex::I   


当complex库被load之后,Numeric类及其子类都会被改变,因为这个时候他们会认为,所有的数都是复数:

puts y = Math.sqrt(-1) #1.oi


2使用mathn

对于对数学计算要求很高的程序,我们可以选择使用mathn标准库。当你require 他的同时,complex, rational,和matrix库 也会被require进来。因为它本身就require了其他的几个库。

mathn库尝试着给出你更合适的结果:
require 'mathn'
puts Math.sqrt(Rational(9,16))    #3/4

puts 1/2                          #1/2
puts Matrix.identity(3)/3                #Matrix[[1/3, 0, 0], [0, 1/3, 0], [0, 0, 1/3]]
puts Math.sqrt(64/25)              #8/5

puts Rational(1,10).inspect            #1/10

mathn 库还给Rational加入了**和power2 方法,他改变了Math.sqrt的行为,因此给他加入了一个Math.rsqrt方法.

3 计算因式分解,最大公约数和最小公倍数

mathn库提供了gcd方法来计算两个数的最大公约数:

puts n = 36.gcd(120)    # 12
puts k = 237.gcd(79)    # 79


prime_division方法提供一个因式分解:
puts 126.prime_division.to_s  #[[2, 1], [3, 2], [7, 1]] 表示2**1 * 3**2 * 7**1 


from_prime_division方法则可以将一个分解了的因式重新组合起来:

factors = [[2,1],[3,2],[7,1]]
puts num = Integer.from_prime_division(factors)


lcm则可以计算两个数的最小公倍数:

puts 10.lcm(5) 


4处理质数

mathn库提供了一个Prime类来处理质数,我们可以使用each来提取指数:

list = []
gen = Prime.new
gen.each do |prime|
  list << prime
  break if list.size == 100
end

puts list.to_s #打印出前100个质数

#和上面的结果一样
list = []
gen = Prime.new
100.times { list << gen.succ }
puts list.to_s


下面的代码可以使我们判断一个数是否为质数:

require 'mathn'

class Integer
  def prime?
    max = Math.sqrt(self).ceil  
    max -= 1 if max % 2 == 0
    pgen = Prime.new
    pgen.each do |factor|
      return false if self % factor == 0
      return true if factor > max
    end
  end
end

31.prime?           # true
237.prime?          # false
1500450271.prime?   # true


5 隐式和显式的数值转换

这节就是解释一下to_i和to_int之间的差别(也包括to_f和to_flt).其实他们之间的差别就h和to_s和to_str之间的差别是一样,也就是说to_int是一个隐式的转换:

class MyClass
  def to_i
    3
  end

  def to_int
    5
  end
end
a=MyClass.new
puts Array.new(a).to_s #[nil, nil, nil, nil, nil]


6Coercing Numeric Values

Coercion也就是一种隐式的转换,当一个方法被传进去了他所不能理解的参数的时候,它会尝试着强迫接收者和参数变为能够相处的类型(比如说你将一个整数和一个浮点数相加它会使用coerce方法将整数和浮点数处理为可以相容的格式(比如都转成整数),然我们这边先定义一个自己的coerce方法,coerce 将会返回一个含有两个数字的数组,它把接收者和参数转换成可以相容的类型.
def coerce(other)
  if other.kind_of?(Float)
    return other, self.to_f
  elsif other.kind_of?(Integer)
    return other, self.to_i
  else
    super
  end
end
class String
  def coerce(n)
    if self['.']
      [n, Float(self)]
    else
      [n, Integer(self)]
    end
  end

end
puts x = 1 + "23"        # 24
puts y = 23 * "1.23"     # 28.29


如果你想创建一些进行算术计算的类时(比如你想要进行罗马数字的计算),我们建议你实现自己的coerce方法。

7 对数字进行按位运算

经常我们想要处理Fixnum作为一个二进制数字.数值类型能够被表示为2进制,8进制和16进制,因此我们能够使用&, |, ^, 和~这些位操作符,来操作位:

x = 0377           # Octal  (decimal 255)
y = 0b00100110     # Binary (decimal  38)
z = 0xBEEF         # Hex    (decimal 48879)

puts a = x | z          # 48895 (bitwise OR)
puts b = x & z          #   239 (bitwise AND)
puts c = x ^ z          # 48656 (bitwise XOR)
puts d = ~ y            #   -39 (negation or 1's complement)

我们可以使用size方法来返回机器所表示的字节数:

puts 1.size #4


ruby中的移位操作都是逻辑移位

x = 8
y = -8

puts a = x >> 2         # 2
puts b = y >> 2         # -2
puts c = x << 2         # 32
puts d = y << 2         # -32


[]能够将一个数值当作一个位数组来对待:

x = 5              # Same as 0b0101
puts a = x[0]           # 1
puts b = x[1]           # 0
puts c = x[2]           # 1
puts d = x[3]           # 0


我们虽然不能直接使用[]=来改变数值的某一位的值,可是我们能够使用移位+逻辑操作来实现:

# We can't do x[3] = 1
# but we can do:
puts x |= (1<<3)
# We can't do x[4] = 0
# but we can do:
puts x &= ~(1<<4)


8 执行进制转换

我们能够使用to_s来转换一个数值的进制,默认不带参数是10进制:
puts 237.to_s(2)            # "11101101"
puts 237.to_s(5)            # "1422"
puts 237.to_s(8)            # "355"
puts 237.to_s               # "237"
puts 237.to_s(16)           # "ed"
puts 237.to_s(30)           # "7r"


我们还能使用%来操作:

puts hex = "%x" % 1234      # "4d2"
puts oct = "%o" % 1234      # "2322"
puts bin = "%b" % 1234      # "10011010010"


当然sprintf也可以进行转换:

str = sprintf(str,"Nietzsche is %x\n",57005)
# str is now: "Nietzsche is dead\n"


9 执行立方根,4次方根,等等

如果我们想得到高次方的根,我们能够使用log的变化就能得到(高数里面的):

x = 531441
puts cuberoot = Math.exp(Math.log(x)/3.0)     # 81.0
puts fourthroot = Math.exp(Math.log(x)/4.0)   # 27.0


当然我们还能使用更简单的方法:

include Math
y = 4096
puts cuberoot = y**(1.0/3.0)      # 16.0
puts fourthroot = y**(1.0/4.0)    # 8.0
puts fourthroot = sqrt(sqrt(y))   # 8.0 (same thing)
puts twelfthroot = y**(1.0/12.0)  # 2.0


10确定机器的大小端

觉得用ruby的话,好麻烦,我就把程序给出来吧,我们这里还有一个自己写的(用c写的),其时用c的话也有好多种方法:

def endianness
  num=0x12345678
  little = "78563412"
  big    = "12345678"
  native = [num].pack('l')
  netunpack = native.unpack('N')[0]
  str = "%8x" % netunpack
  case str
    when little
      "LITTLE"
    when big
      "BIG"
    else
      "OTHER"
  end
end

puts endianness   # In this case, prints "LITTLE"


int is_little_endian()
{
	int a=1;
	return *(char *)&a;
}


或者说用一个union来写,更漂亮...
评论
发表评论

您还没有登录,请登录后发表评论

simohayha
搜索本博客
存档
最新评论