File size: 5,340 Bytes
b200bda
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from mpmath.libmp import *
from mpmath import mpf, mp

from random import randint, choice, seed

all_modes = [round_floor, round_ceiling, round_down, round_up, round_nearest]

fb = from_bstr
fi = from_int
ff = from_float


def test_div_1_3():
    a = fi(1)
    b = fi(3)
    c = fi(-1)

    # floor rounds down, ceiling rounds up
    assert mpf_div(a, b, 7, round_floor)   == fb('0.01010101')
    assert mpf_div(a, b, 7, round_ceiling) == fb('0.01010110')
    assert mpf_div(a, b, 7, round_down)    == fb('0.01010101')
    assert mpf_div(a, b, 7, round_up)      == fb('0.01010110')
    assert mpf_div(a, b, 7, round_nearest) == fb('0.01010101')

    # floor rounds up, ceiling rounds down
    assert mpf_div(c, b, 7, round_floor)   == fb('-0.01010110')
    assert mpf_div(c, b, 7, round_ceiling) == fb('-0.01010101')
    assert mpf_div(c, b, 7, round_down)    == fb('-0.01010101')
    assert mpf_div(c, b, 7, round_up)      == fb('-0.01010110')
    assert mpf_div(c, b, 7, round_nearest) == fb('-0.01010101')

def test_mpf_divi_1_3():
    a = 1
    b = fi(3)
    c = -1
    assert mpf_rdiv_int(a, b, 7, round_floor)   == fb('0.01010101')
    assert mpf_rdiv_int(a, b, 7, round_ceiling) == fb('0.01010110')
    assert mpf_rdiv_int(a, b, 7, round_down)    == fb('0.01010101')
    assert mpf_rdiv_int(a, b, 7, round_up)      == fb('0.01010110')
    assert mpf_rdiv_int(a, b, 7, round_nearest) == fb('0.01010101')
    assert mpf_rdiv_int(c, b, 7, round_floor)   == fb('-0.01010110')
    assert mpf_rdiv_int(c, b, 7, round_ceiling) == fb('-0.01010101')
    assert mpf_rdiv_int(c, b, 7, round_down)    == fb('-0.01010101')
    assert mpf_rdiv_int(c, b, 7, round_up)      == fb('-0.01010110')
    assert mpf_rdiv_int(c, b, 7, round_nearest) == fb('-0.01010101')


def test_div_300():

    q = fi(1000000)
    a = fi(300499999)    # a/q is a little less than a half-integer
    b = fi(300500000)    # b/q exactly a half-integer
    c = fi(300500001)    # c/q is a little more than a half-integer

    # Check nearest integer rounding (prec=9 as 2**8 < 300 < 2**9)

    assert mpf_div(a, q, 9, round_down) == fi(300)
    assert mpf_div(b, q, 9, round_down) == fi(300)
    assert mpf_div(c, q, 9, round_down) == fi(300)
    assert mpf_div(a, q, 9, round_up) == fi(301)
    assert mpf_div(b, q, 9, round_up) == fi(301)
    assert mpf_div(c, q, 9, round_up) == fi(301)

    # Nearest even integer is down
    assert mpf_div(a, q, 9, round_nearest) == fi(300)
    assert mpf_div(b, q, 9, round_nearest) == fi(300)
    assert mpf_div(c, q, 9, round_nearest) == fi(301)

    # Nearest even integer is up
    a = fi(301499999)
    b = fi(301500000)
    c = fi(301500001)
    assert mpf_div(a, q, 9, round_nearest) == fi(301)
    assert mpf_div(b, q, 9, round_nearest) == fi(302)
    assert mpf_div(c, q, 9, round_nearest) == fi(302)


def test_tight_integer_division():
    # Test that integer division at tightest possible precision is exact
    N = 100
    seed(1)
    for i in range(N):
        a = choice([1, -1]) * randint(1, 1<<randint(10, 100))
        b = choice([1, -1]) * randint(1, 1<<randint(10, 100))
        p = a * b
        width = bitcount(abs(b)) - trailing(b)
        a = fi(a); b = fi(b); p = fi(p)
        for mode in all_modes:
            assert mpf_div(p, a, width, mode) == b


def test_epsilon_rounding():
    # Verify that mpf_div uses infinite precision; this result will
    # appear to be exactly 0.101 to a near-sighted algorithm

    a = fb('0.101' + ('0'*200) + '1')
    b = fb('1.10101')
    c = mpf_mul(a, b, 250, round_floor) # exact
    assert mpf_div(c, b, bitcount(a[1]), round_floor) == a # exact

    assert mpf_div(c, b, 2, round_down) == fb('0.10')
    assert mpf_div(c, b, 3, round_down) == fb('0.101')
    assert mpf_div(c, b, 2, round_up) == fb('0.11')
    assert mpf_div(c, b, 3, round_up) == fb('0.110')
    assert mpf_div(c, b, 2, round_floor) == fb('0.10')
    assert mpf_div(c, b, 3, round_floor) == fb('0.101')
    assert mpf_div(c, b, 2, round_ceiling) == fb('0.11')
    assert mpf_div(c, b, 3, round_ceiling) == fb('0.110')

    # The same for negative numbers
    a = fb('-0.101' + ('0'*200) + '1')
    b = fb('1.10101')
    c = mpf_mul(a, b, 250, round_floor)
    assert mpf_div(c, b, bitcount(a[1]), round_floor) == a

    assert mpf_div(c, b, 2, round_down) == fb('-0.10')
    assert mpf_div(c, b, 3, round_up) == fb('-0.110')

    # Floor goes up, ceiling goes down
    assert mpf_div(c, b, 2, round_floor) == fb('-0.11')
    assert mpf_div(c, b, 3, round_floor) == fb('-0.110')
    assert mpf_div(c, b, 2, round_ceiling) == fb('-0.10')
    assert mpf_div(c, b, 3, round_ceiling) == fb('-0.101')


def test_mod():
    mp.dps = 15
    assert mpf(234) % 1 == 0
    assert mpf(-3) % 256 == 253
    assert mpf(0.25) % 23490.5 == 0.25
    assert mpf(0.25) % -23490.5 == -23490.25
    assert mpf(-0.25) % 23490.5 == 23490.25
    assert mpf(-0.25) % -23490.5 == -0.25
    # Check that these cases are handled efficiently
    assert mpf('1e10000000000') % 1 == 0
    assert mpf('1.23e-1000000000') % 1 == mpf('1.23e-1000000000')
    # test __rmod__
    assert 3 % mpf('1.75') == 1.25

def test_div_negative_rnd_bug():
    mp.dps = 15
    assert (-3) / mpf('0.1531879017645047') == mpf('-19.583791966887116')
    assert mpf('-2.6342475750861301') / mpf('0.35126216427941814') == mpf('-7.4993775104985909')