forked from M-Labs/artiq
compiler: correct semantics of floating point % operator (fix #830).
This commit is contained in:
parent
62f2693e36
commit
491c7ef898
@ -400,8 +400,7 @@ class LLVMIRGenerator:
|
||||
*/
|
||||
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
|
||||
xmody += y;
|
||||
--xdivy;
|
||||
assert(xmody && ((y ^ xmody) >= 0));
|
||||
// ...
|
||||
}
|
||||
"""
|
||||
llx, lly = llfun.args
|
||||
@ -417,7 +416,45 @@ class LLVMIRGenerator:
|
||||
llbuilder.ret(llbuilder.add(llxremy, lly))
|
||||
llbuilder.ret(llxremy)
|
||||
elif name == "__py_moddf4":
|
||||
assert False
|
||||
"""
|
||||
Reference Objects/floatobject.c
|
||||
mod = fmod(vx, wx);
|
||||
/* fmod is typically exact, so vx-mod is *mathematically* an
|
||||
exact multiple of wx. But this is fp arithmetic, and fp
|
||||
vx - mod is an approximation; the result is that div may
|
||||
not be an exact integral value after the division, although
|
||||
it will always be very close to one.
|
||||
*/
|
||||
// ...
|
||||
if (mod) {
|
||||
/* ensure the remainder has the same sign as the denominator */
|
||||
if ((wx < 0) != (mod < 0)) {
|
||||
mod += wx;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* the remainder is zero, and in the presence of signed zeroes
|
||||
fmod returns different results across platforms; ensure
|
||||
it has the same sign as the denominator; we'd like to do
|
||||
"mod = wx * 0.0", but that may get optimized away */
|
||||
mod *= mod; /* hide "mod = +0" from optimizer */
|
||||
if (wx < 0.0)
|
||||
mod = -mod;
|
||||
}
|
||||
"""
|
||||
llv, llw = llfun.args
|
||||
llrem = llbuilder.frem(llv, llw)
|
||||
|
||||
llremnonzero = llbuilder.fcmp_unordered('!=', llrem, ll.Constant(lldouble, 0.0))
|
||||
llwltzero = llbuilder.fcmp_ordered('<', llw, ll.Constant(lldouble, 0.0))
|
||||
llremltzero = llbuilder.fcmp_ordered('<', llrem, ll.Constant(lldouble, 0.0))
|
||||
lldiffsign = llbuilder.icmp_unsigned('!=', llwltzero, llremltzero)
|
||||
|
||||
llcond = llbuilder.and_(llremnonzero, lldiffsign)
|
||||
with llbuilder.if_then(llcond):
|
||||
llbuilder.ret(llbuilder.fadd(llrem, llw))
|
||||
llbuilder.ret(llrem)
|
||||
|
||||
def get_function(self, typ, name):
|
||||
llfun = self.llmodule.get_global(name)
|
||||
|
@ -26,10 +26,10 @@ assert -1 % 8 == 7
|
||||
#ARTIQ#assert int64(3) % -2 == -1
|
||||
#ARTIQ#assert int64(-3) % -2 == -1
|
||||
assert -1 % 8 == 7
|
||||
# assert 3.0 % 2.0 == 1.0
|
||||
# assert -3.0 % 2.0 == 1.0
|
||||
# assert 3.0 % -2.0 == -1.0
|
||||
# assert -3.0 % -2.0 == -1.0
|
||||
assert 3.0 % 2.0 == 1.0
|
||||
assert -3.0 % 2.0 == 1.0
|
||||
assert 3.0 % -2.0 == -1.0
|
||||
assert -3.0 % -2.0 == -1.0
|
||||
assert 3 ** 2 == 9
|
||||
assert 3.0 ** 2.0 == 9.0
|
||||
assert 9.0 ** 0.5 == 3.0
|
||||
|
Loading…
Reference in New Issue
Block a user