Skip to content

Commit 64a789b

Browse files
committed
Implement BigMath.atan2(y, x, prec)
1 parent 6f61b71 commit 64a789b

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

lib/bigdecimal/math.rb

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
# cos (x, prec)
1010
# tan (x, prec)
1111
# atan(x, prec)
12+
# atan2(y, x, prec)
1213
# PI (prec)
1314
# E (prec) == exp(1.0,prec)
1415
#
1516
# where:
16-
# x ... BigDecimal number to be computed.
17+
# x, y ... BigDecimal number to be computed.
1718
# prec ... Number of digits to be obtained.
1819
#++
1920
#
@@ -211,6 +212,36 @@ def atan(x, prec)
211212
y
212213
end
213214

215+
# call-seq:
216+
# atan2(decimal, decimal, numeric) -> BigDecimal
217+
#
218+
# Computes the arctangent of y and x to the specified number of digits of
219+
# precision, +numeric+.
220+
#
221+
# BigMath.atan2(BigDecimal('-1'), BigDecimal('1'), 16).to_s
222+
# #=> "-0.785398163397448309615660845819878471907514682065e0"
223+
#
224+
def atan2(y, x, prec)
225+
if x.infinite? || y.infinite?
226+
one = BigDecimal(1)
227+
zero = BigDecimal(0)
228+
x = x.infinite? ? (x > 0 ? one : -one) : zero
229+
y = y.infinite? ? (y > 0 ? one : -one) : y.sign * zero
230+
end
231+
232+
return x.sign >= 0 ? BigDecimal(0) : y.sign * PI(prec) if y.zero?
233+
234+
y = -y if neg = y < 0
235+
xlarge = y.abs < x.abs
236+
divprec = prec + BigDecimal.double_fig
237+
if x > 0
238+
v = xlarge ? atan(y.div(x, divprec), prec) : PI(prec) / 2 - atan(x.div(y, divprec), prec)
239+
else
240+
v = xlarge ? PI(prec) - atan(-y.div(x, divprec), prec) : PI(prec) / 2 + atan(x.div(-y, divprec), prec)
241+
end
242+
neg ? -v : v
243+
end
244+
214245
# call-seq:
215246
# PI(numeric) -> BigDecimal
216247
#

test/bigdecimal/test_bigmath.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,25 @@ def test_atan
115115
assert_relative_precision {|n| atan(BigDecimal("1e30"), n)}
116116
end
117117

118+
def test_atan2
119+
zero = BigDecimal(0)
120+
one = BigDecimal(1)
121+
assert_equal(0, atan2(zero, zero, N))
122+
assert_equal(0, atan2(zero, one, N))
123+
[MINF, -one, -zero, zero, one, PINF].repeated_permutation(2) do |y, x|
124+
assert_in_delta(Math::atan2(y.to_f, x.to_f), atan2(y, x, N))
125+
end
126+
assert_in_delta(PI(100), atan2(zero, -one, 100), BigDecimal("1e-100"))
127+
assert_in_delta(PI(100) / 2, atan2(one, zero, 100), BigDecimal("1e-100"))
128+
assert_in_delta(-PI(100) / 2, atan2(-one, zero, 100), BigDecimal("1e-100"))
129+
assert_in_delta(PI(100) / 3, atan2(BigDecimal(3), SQRT3, 100), BigDecimal("1e-100"))
130+
assert_in_delta(PI(100) / 6, atan2(SQRT3, BigDecimal(3), 100), BigDecimal("1e-100"))
131+
['-1e20', '-2', '-1e-30', '1e-30', '2', '1e20'].repeated_permutation(2) do |y, x|
132+
assert_in_delta(Math.atan2(y.to_f, x.to_f), atan2(BigDecimal(y), BigDecimal(x), N))
133+
assert_relative_precision {|n| atan2(BigDecimal(y), BigDecimal(x), n) }
134+
end
135+
end
136+
118137
def test_log
119138
assert_equal(0, BigMath.log(BigDecimal("1.0"), 10))
120139
assert_in_epsilon(Math.log(10)*1000, BigMath.log(BigDecimal("1e1000"), 10))

0 commit comments

Comments
 (0)