Skip to content

Commit 0bccfda

Browse files
committed
Implement BigMath.atan2(y, x, prec)
1 parent b947195 commit 0bccfda

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
#
@@ -197,6 +198,36 @@ def atan(x, prec)
197198
y
198199
end
199200

201+
# call-seq:
202+
# atan2(decimal, decimal, numeric) -> BigDecimal
203+
#
204+
# Computes the arctangent of y and x to the specified number of digits of
205+
# precision, +numeric+.
206+
#
207+
# BigMath.atan(BigDecimal('-1'), 16).to_s
208+
# #=> "-0.785398163397448309615660845819878471907514682065e0"
209+
#
210+
def atan2(y, x, prec)
211+
if x.infinite? || y.infinite?
212+
one = BigDecimal(1)
213+
zero = BigDecimal(0)
214+
x = x.infinite? ? (x > 0 ? one : -one) : zero
215+
y = y.infinite? ? (y > 0 ? one : -one) : y.sign * zero
216+
end
217+
218+
return x.sign >= 0 ? BigDecimal(0) : y.sign * PI(prec) if y.zero?
219+
220+
y = -y if neg = y < 0
221+
xlarge = y.abs < x.abs
222+
divprec = prec + BigDecimal.double_fig
223+
if x > 0
224+
v = xlarge ? atan(y.div(x, divprec), prec) : PI(prec) / 2 - atan(x.div(y, divprec), prec)
225+
else
226+
v = xlarge ? PI(prec) - atan(-y.div(x, divprec), prec) : PI(prec) / 2 + atan(x.div(-y, divprec), prec)
227+
end
228+
neg ? -v : v
229+
end
230+
200231
# call-seq:
201232
# PI(numeric) -> BigDecimal
202233
#

test/bigdecimal/test_bigmath.rb

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

110+
def test_atan2
111+
zero = BigDecimal(0)
112+
one = BigDecimal(1)
113+
assert_equal(0, atan2(zero, zero, N))
114+
assert_equal(0, atan2(zero, one, N))
115+
[MINF, -one, -zero, zero, one, PINF].repeated_permutation(2) do |y, x|
116+
assert_in_delta(Math::atan2(y.to_f, x.to_f), atan2(y, x, N))
117+
end
118+
assert_in_delta(PI(100), atan2(zero, -one, 100), BigDecimal("1e-100"))
119+
assert_in_delta(PI(100) / 2, atan2(one, zero, 100), BigDecimal("1e-100"))
120+
assert_in_delta(-PI(100) / 2, atan2(-one, zero, 100), BigDecimal("1e-100"))
121+
assert_in_delta(PI(100) / 3, atan2(BigDecimal(3), SQRT3, 100), BigDecimal("1e-100"))
122+
assert_in_delta(PI(100) / 6, atan2(SQRT3, BigDecimal(3), 100), BigDecimal("1e-100"))
123+
['-1e20', '-2', '-1e-30', '1e-30', '2', '1e20'].repeated_permutation(2) do |y, x|
124+
assert_in_delta(Math.atan2(y.to_f, x.to_f), atan2(BigDecimal(y), BigDecimal(x), N))
125+
assert_relative_precision {|n| atan2(BigDecimal(y), BigDecimal(x), n) }
126+
end
127+
end
128+
110129
def test_log
111130
assert_equal(0, BigMath.log(BigDecimal("1.0"), 10))
112131
assert_in_epsilon(Math.log(10)*1000, BigMath.log(BigDecimal("1e1000"), 10))

0 commit comments

Comments
 (0)