Skip to content

Commit 21c82b3

Browse files
authored
Arithmetics: Implement Base.inv (#104)
1 parent 8771f35 commit 21c82b3

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

src/Decimals.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ include("conversion.jl")
2727
include("decimal.jl")
2828
include("arithmetic/elementary.jl")
2929
include("arithmetic/exceptions.jl")
30+
include("arithmetic/inv.jl")
3031
include("arithmetic/sqrt.jl")
3132
include("equals.jl")
3233
include("round.jl")

src/arithmetic/inv.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
function Base.inv(x::Decimal)
2+
if iszero(x)
3+
throw(DivisionByZeroError())
4+
elseif isone(x)
5+
return x
6+
end
7+
8+
prec = precision(Decimal)
9+
10+
# inv(x) = inv(c) * inv(10^q)
11+
# = inv(c) * 10^-q
12+
# = inv(c) * 10^t * 10^(-q - t)
13+
# = 10^t / c * 10^(-q - t)
14+
#
15+
# We pick `t` such that
16+
#
17+
# 10^t ÷ c
18+
#
19+
# has at least `prec + 1` digits (an extra digit for dealing with
20+
# rounding).
21+
t = prec + ndigits(x.c) + 1
22+
23+
c, rem = divrem(BigTen^t, x.c)
24+
q = -x.q - t
25+
26+
# When the result is non-exact, and the last coefficient digit is 5, we
27+
# need to increment the coefficient for correct rounding
28+
if rem > 0 && isdivisible(c, 5)
29+
c += 1
30+
end
31+
32+
c, m = cancelfactor(c, Val(10))
33+
q = q + m
34+
35+
return fix(Decimal(x.s, c, q))
36+
end

test/arithmetic/test_inv.jl

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using Decimals
2+
using Test
3+
4+
@testset "inv" begin
5+
# Taken from dectests for division
6+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1") == dec"1")
7+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"2") == dec"0.5")
8+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"3") == dec"0.333333333")
9+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"2") == dec"0.5")
10+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"4") == dec"0.25")
11+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"8") == dec"0.125")
12+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"16") == dec"0.0625")
13+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"32") == dec"0.03125")
14+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"64") == dec"0.015625")
15+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-2") == dec"-0.5")
16+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-4") == dec"-0.25")
17+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-8") == dec"-0.125")
18+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-16") == dec"-0.0625")
19+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-32") == dec"-0.03125")
20+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"-64") == dec"-0.015625")
21+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e-8") == dec"1e+8")
22+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e-9") == dec"1e+9")
23+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e-10") == dec"1e+10")
24+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e-11") == dec"1e+11")
25+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e-12") == dec"1e+12")
26+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1") == dec"1")
27+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"2") == dec"0.5")
28+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"3") == dec"0.333333333")
29+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"4") == dec"0.25")
30+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"5") == dec"0.2")
31+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"6") == dec"0.166666667")
32+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"7") == dec"0.142857143")
33+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"8") == dec"0.125")
34+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"9") == dec"0.111111111")
35+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"10") == dec"0.1")
36+
@with_context (Emax = 384, Emin = -383, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1") == dec"1")
37+
@with_context (Emax = 999999999, Emin = -999999999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1e999999999") == dec"1e-999999999")
38+
@with_context (Emax = 999999999, Emin = -999999999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"0.9e999999999") == dec"1.11111111e-999999999")
39+
@with_context (Emax = 999999999, Emin = -999999999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"0.99e999999999") == dec"1.01010101e-999999999")
40+
@with_context (Emax = 999999999, Emin = -999999999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"0.999999999e999999999") == dec"1.00000000e-999999999")
41+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"12345678000") == dec"8.10000066e-11")
42+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567800") == dec"8.10000066e-10")
43+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567890") == dec"8.10000007e-10")
44+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567891") == dec"8.10000007e-10")
45+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"12345678901") == dec"8.10000007e-11")
46+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567896") == dec"8.10000003e-10")
47+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567897") == dec"8.10000003e-10")
48+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567898") == dec"8.10000002e-10")
49+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567899") == dec"8.10000001e-10")
50+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567900") == dec"8.10000001e-10")
51+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567901") == dec"8.10000000e-10")
52+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567902") == dec"8.09999999e-10")
53+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567896.000000000000") == dec"8.10000003e-10")
54+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567896.000000000001") == dec"8.10000003e-10")
55+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567896.000000000000000000000000000000000000000009") == dec"8.10000003e-10")
56+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567897.900010000000000000000000000000000000000009") == dec"8.10000002e-10")
57+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"12345678000") == dec"8.10000066420005e-11")
58+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567800") == dec"8.10000066420005e-10")
59+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567890") == dec"8.10000007371000e-10")
60+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567891") == dec"8.10000006714900e-10")
61+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"12345678901") == dec"8.10000007305390e-11")
62+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1234567896") == dec"8.10000003434400e-10")
63+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1.0e+33") == dec"1e-33")
64+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"10e+33") == dec"1e-34")
65+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"1.0e-33") == dec"1e+33")
66+
@with_context (Emax = 999, Emin = -999, precision = 15, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"10e-33") == dec"1e+32")
67+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"9.9") == dec"0.101010101")
68+
@with_context (Emax = 999, Emin = -999, precision = 8, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"9.9") == dec"0.10101010")
69+
@with_context (Emax = 999, Emin = -999, precision = 7, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"9.9") == dec"0.1010101")
70+
@with_context (Emax = 999, Emin = -999, precision = 6, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"9.9") == dec"0.101010")
71+
@with_context (Emax = 999, Emin = -999, precision = 9, rounding = RoundingMode{:NearestTiesAway}()) @test(inv(dec"2") == dec"0.5")
72+
@with_context (Emax = 384, Emin = -383, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"0"))
73+
@with_context (Emax = 384, Emin = -383, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"-0"))
74+
@with_context (Emax = 384, Emin = -383, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"0.0"))
75+
@with_context (Emax = 384, Emin = -383, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"-0.0"))
76+
@with_context (Emax = 999999999, Emin = -999999999, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"0"))
77+
@with_context (Emax = 999999999, Emin = -999999999, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"0.0"))
78+
@with_context (Emax = 999999999, Emin = -999999999, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"-0"))
79+
@with_context (Emax = 999999999, Emin = -999999999, precision = 16, rounding = RoundingMode{:NearestTiesAway}()) @test_throws(DivisionByZeroError, inv(dec"-0.0"))
80+
end
81+

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ include("test_round.jl")
1414
include("test_show.jl")
1515

1616
include("arithmetic/test_sqrt.jl")
17+
include("arithmetic/test_inv.jl")
1718

1819
@testset "DecTests" begin
1920
include("dectests/test_abs.jl")

0 commit comments

Comments
 (0)