Skip to content

Commit e4cb73b

Browse files
committed
Fix off-by-one error in rounding truncation in calculate_inverse_coeff()
We must use the precise value of 2^nbits(T) in order to get the correct division in all cases. ....... UGH except now the Int64 tests aren't passing.
1 parent 27a3e0f commit e4cb73b

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

src/fldmod-by-const.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ Base.@assume_effects :foldable function calculate_inverse_coeff(::Type{T}, C) wh
119119
# Now, truncate to only the upper half of invcoeff, after we've shifted. Instead of
120120
# bitshifting, we round to maintain precision. (This is needed to prevent off-by-ones.)
121121
# -- This is equivalent to `invcoeff = T(invcoeff >> sizeof(T))`, except rounded. --
122-
invcoeff = _round_to_nearest(fldmod(invcoeff, typemax(UT))..., typemax(UT)) % T
122+
two_to_N = _widen(typemax(UT)) + UT(1) # Precise value for 2^nbits(T) (doesn't fit in T)
123+
invcoeff = _round_to_nearest(fldmod(invcoeff, two_to_N)..., two_to_N ) % T
123124
return invcoeff, toshift
124125
end
125126

test/fldmod-by-const_tests.jl

+24
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,30 @@ end
5757
end
5858
end
5959

60+
@testset "fixed decimal multiplication - exhaustive 8-bit" begin
61+
@testset for P in (0,1)
62+
@testset for T in (Int8, UInt8)
63+
FD = FixedDecimal{T,P}
64+
65+
function test_multiplies_correctly(fd, x)
66+
big = FixedDecimal{BigInt, P}(fd)
67+
big_mul = big * x
68+
# This might overflow: ...
69+
mul = fd * x
70+
@testset "$fd * $x" begin
71+
# ... so we truncate big to the same size
72+
@test big_mul.i % T == mul.i % T
73+
end
74+
end
75+
@testset for v in typemin(FD) : eps(FD) : typemax(FD)
76+
@testset for v2 in typemin(FD) : eps(FD) : typemax(FD)
77+
test_multiplies_correctly(v, v2)
78+
end
79+
end
80+
end
81+
end
82+
end
83+
6084
@testset "fixed decimal multiplication - exhaustive 16-bit" begin
6185
@testset for P in (0,1,2,3,4)
6286
@testset for T in (Int16, UInt16)

0 commit comments

Comments
 (0)