ruby way之数值计算之二

本文介绍了如何使用Ruby标准库complex处理复数,并演示了mathn库提供的高级数学计算功能,包括根计算、因式分解、最大公约数和最小公倍数等。
1 处理复数

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

puts Complex(1,2) # 3+5i[/code]

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

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

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

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

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

[code]puts y = Math.sqrt(-1) #1.oi[/code]

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方法来计算两个数的最大公约数:

[code]puts n = 36.gcd(120) # 12
puts k = 237.gcd(79) # 79[/code]

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

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

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

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

[code]puts 10.lcm(5) [/code]

4处理质数

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

[code]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[/code]

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

[code]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[/code]

5 隐式和显式的数值转换

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

[code]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]
[/code]

6Coercing Numeric Values

Coercion也就是一种隐式的转换,当一个方法被传进去了他所不能理解的参数的时候,它会尝试着强迫接收者和参数变为能够相处的类型(比如说你将一个整数和一个浮点数相加它会使用coerce方法将整数和浮点数处理为可以相容的格式(比如都转成整数),然我们这边先定义一个自己的coerce方法,coerce 将会返回一个含有两个数字的数组,它把接收者和参数转换成可以相容的类型.
[code]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[/code]

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

7 对数字进行按位运算

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

[code]
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)[/code]
我们可以使用size方法来返回机器所表示的字节数:

[code]puts 1.size #4[/code]

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

[code]x = 8
y = -8

puts a = x >> 2 # 2
puts b = y >> 2 # -2
puts c = x << 2 # 32
puts d = y << 2 # -32[/code]

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

[code]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[/code]

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

[code]# 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)[/code]

8 执行进制转换

我们能够使用to_s来转换一个数值的进制,默认不带参数是10进制:
[code]
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"[/code]

我们还能使用%来操作:

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

当然sprintf也可以进行转换:

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

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

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

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

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

[code]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[/code]

10确定机器的大小端

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

[code]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"[/code]

[code]int is_little_endian()
{
int a=1;
return *(char *)&a;
}[/code]

或者说用一个union来写,更漂亮...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值