Module: BigMath

Defined in:
lib/bigdecimal/math.rb

Overview

-- Contents:

sqrt(x, prec)
sin (x, prec)
cos (x, prec)
atan(x, prec)  Note: |x|<1, x=0.9999 may not converge.
exp (x, prec)
log (x, prec)
PI  (prec)
E   (prec) == exp(1.0,prec)

where:

x    ... BigDecimal number to be computed.
         |x| must be small enough to get convergence.
prec ... Number of digits to be obtained.

++

Provides mathematical functions.

Example:

require "bigdecimal"
require "bigdecimal/math"

include BigMath

a = BigDecimal((PI(100)/2).to_s)
puts sin(a,100) # -> 0.10000000000000000000......E1

Instance Method Summary collapse

Instance Method Details

#atan(x, prec) ⇒ Object

Computes the arctangent of x to the specified number of digits of precision.

If x is infinite or NaN, returns NaN. Raises an argument error if x > 1.

Raises:

  • (ArgumentError)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/bigdecimal/math.rb', line 103

def atan(x, prec)
  raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  raise ArgumentError, "x.abs must be less than 1.0" if x.abs>=1
  n    = prec + BigDecimal.double_fig
  y = x
  d = y
  t = x
  r = BigDecimal("3")
  x2 = x.mult(x,n)
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t = -t.mult(x2,n)
    d = t.div(r,m)
    y += d
    r += 2
  end
  y
end

#cos(x, prec) ⇒ Object

Computes the cosine of x to the specified number of digits of precision.

If x is infinite or NaN, returns NaN.

Raises:

  • (ArgumentError)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/bigdecimal/math.rb', line 74

def cos(x, prec)
  raise ArgumentError, "Zero or negative precision for cos" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  two  = BigDecimal("2")
  x1 = one
  x2 = x.mult(x,n)
  sign = 1
  y = one
  d = y
  i = BigDecimal("0")
  z = one
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    sign = -sign
    x1  = x2.mult(x1,n)
    i  += two
    z  *= (i-one) * i
    d   = sign * x1.div(z,m)
    y  += d
  end
  y
end

#E(prec) ⇒ Object

Computes e (the base of natural logarithms) to the specified number of digits of precision.

Raises:

  • (ArgumentError)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/bigdecimal/math.rb', line 218

def E(prec)
  raise ArgumentError, "Zero or negative precision for E" if prec <= 0
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  y  = one
  d  = y
  z  = one
  i  = 0
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    i += 1
    z *= i
    d  = one.div(z,m)
    y += d
  end
  y
end

#exp(x, prec) ⇒ Object

Computes the value of e (the base of natural logarithms) raised to the power of x, to the specified number of digits of precision.

If x is infinite or NaN, returns NaN.

BigMath::exp(BigDecimal.new('1'), 10).to_s -> "0.271828182845904523536028752390026306410273E1"

Raises:

  • (ArgumentError)


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/bigdecimal/math.rb', line 130

def exp(x, prec)
  raise ArgumentError, "Zero or negative precision for exp" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  x1 = one
  y  = one
  d  = y
  z  = one
  i  = 0
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    x1  = x1.mult(x,n)
    i += 1
    z *= i
    d  = x1.div(z,m)
    y += d
  end
  y
end

#log(x, prec) ⇒ Object

Computes the natural logarithm of x to the specified number of digits of precision.

Returns x if x is infinite or NaN.

Raises:

  • (ArgumentError)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/bigdecimal/math.rb', line 156

def log(x, prec)
  raise ArgumentError, "Zero or negative argument for log" if x <= 0 || prec <= 0
  return x if x.infinite? || x.nan?
  one = BigDecimal("1")
  two = BigDecimal("2")
  n  = prec + BigDecimal.double_fig
  x  = (x - one).div(x + one,n)
  x2 = x.mult(x,n)
  y  = x
  d  = y
  i = one
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    x  = x2.mult(x,n)
    i += two
    d  = x.div(i,m)
    y += d
  end
  y*two
end

#PI(prec) ⇒ Object

Computes the value of pi to the specified number of digits of precision.

Raises:

  • (ArgumentError)


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/bigdecimal/math.rb', line 178

def PI(prec)
  raise ArgumentError, "Zero or negative argument for PI" if prec <= 0
  n      = prec + BigDecimal.double_fig
  zero   = BigDecimal("0")
  one    = BigDecimal("1")
  two    = BigDecimal("2")

  m25    = BigDecimal("-0.04")
  m57121 = BigDecimal("-57121")

  pi     = zero

  d = one
  k = one
  w = one
  t = BigDecimal("-80")
  while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t   = t*m25
    d   = t.div(k,m)
    k   = k+two
    pi  = pi + d
  end

  d = one
  k = one
  w = one
  t = BigDecimal("956")
  while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    t   = t.div(m57121,n)
    d   = t.div(k,m)
    pi  = pi + d
    k   = k+two
  end
  pi
end

#sin(x, prec) ⇒ Object

Computes the sine of x to the specified number of digits of precision.

If x is infinite or NaN, returns NaN.

Raises:

  • (ArgumentError)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/bigdecimal/math.rb', line 46

def sin(x, prec)
  raise ArgumentError, "Zero or negative precision for sin" if prec <= 0
  return BigDecimal("NaN") if x.infinite? || x.nan?
  n    = prec + BigDecimal.double_fig
  one  = BigDecimal("1")
  two  = BigDecimal("2")
  x1   = x
  x2   = x.mult(x,n)
  sign = 1
  y    = x
  d    = y
  i    = one
  z    = one
  while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
    m = BigDecimal.double_fig if m < BigDecimal.double_fig
    sign = -sign
    x1  = x2.mult(x1,n)
    i  += two
    z  *= (i-one) * i
    d   = sign * x1.div(z,m)
    y  += d
  end
  y
end

#sqrt(x, prec) ⇒ Object

Computes the square root of x to the specified number of digits of precision.

BigDecimal.new('2').sqrt(16).to_s

-> "0.14142135623730950488016887242096975E1"


39
40
41
# File 'lib/bigdecimal/math.rb', line 39

def sqrt(x,prec)
  x.sqrt(prec)
end