Skip to content

Commit 5b847e4

Browse files
committed
Implement BigMath.atan2(y, x, prec)
1 parent 7741035 commit 5b847e4

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
#
@@ -200,6 +201,36 @@ def atan(x, prec)
200201
y
201202
end
202203

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

test/bigdecimal/test_bigmath.rb

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

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

0 commit comments

Comments
 (0)