2007-12-19
ruby way之数值计算之二
1 处理复数
标准库complex 能使我们处理复数。一个复数的创建能使用Complex来构造:
方法im能够转换一个数字为虚数:
如果你想表示极坐标的话,可以使用polar方法:
Complex还提供了I这个常量,他就表示复数中的i:
当complex库被load之后,Numeric类及其子类都会被改变,因为这个时候他们会认为,所有的数都是复数:
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方法来计算两个数的最大公约数:
prime_division方法提供一个因式分解:
from_prime_division方法则可以将一个分解了的因式重新组合起来:
lcm则可以计算两个数的最小公倍数:
4处理质数
mathn库提供了一个Prime类来处理质数,我们可以使用each来提取指数:
下面的代码可以使我们判断一个数是否为质数:
5 隐式和显式的数值转换
这节就是解释一下to_i和to_int之间的差别(也包括to_f和to_flt).其实他们之间的差别就h和to_s和to_str之间的差别是一样,也就是说to_int是一个隐式的转换:
6Coercing Numeric Values
Coercion也就是一种隐式的转换,当一个方法被传进去了他所不能理解的参数的时候,它会尝试着强迫接收者和参数变为能够相处的类型(比如说你将一个整数和一个浮点数相加它会使用coerce方法将整数和浮点数处理为可以相容的格式(比如都转成整数),然我们这边先定义一个自己的coerce方法,coerce 将会返回一个含有两个数字的数组,它把接收者和参数转换成可以相容的类型.
如果你想创建一些进行算术计算的类时(比如你想要进行罗马数字的计算),我们建议你实现自己的coerce方法。
7 对数字进行按位运算
经常我们想要处理Fixnum作为一个二进制数字.数值类型能够被表示为2进制,8进制和16进制,因此我们能够使用&, |, ^, 和~这些位操作符,来操作位:
我们可以使用size方法来返回机器所表示的字节数:
ruby中的移位操作都是逻辑移位
[]能够将一个数值当作一个位数组来对待:
我们虽然不能直接使用[]=来改变数值的某一位的值,可是我们能够使用移位+逻辑操作来实现:
8 执行进制转换
我们能够使用to_s来转换一个数值的进制,默认不带参数是10进制:
我们还能使用%来操作:
当然sprintf也可以进行转换:
9 执行立方根,4次方根,等等
如果我们想得到高次方的根,我们能够使用log的变化就能得到(高数里面的):
当然我们还能使用更简单的方法:
10确定机器的大小端
觉得用ruby的话,好麻烦,我就把程序给出来吧,我们这里还有一个自己写的(用c写的),其时用c的话也有好多种方法:
或者说用一个union来写,更漂亮...
标准库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来写,更漂亮...







评论排行榜