Skip to content

Commit

Permalink
Dealing with integers for abs
Browse files Browse the repository at this point in the history
  • Loading branch information
Agathe Herrou committed Mar 8, 2024
1 parent b1fd2e8 commit 952c910
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 0 deletions.
12 changes: 12 additions & 0 deletions PRECISION.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ Here we explain the logic behind the implementation of precision inference in ea

abs is a function that is equal to the identity function on positive values and its opposite on negative values. As such, its output precision should be the same as its input precision.

### Integers

When applied to integers, Abs is implemented using the `std::abs` C++ function.
This function has undefined behaviour when applied to `INT_MIN`, since `-INT_MIN = INT_MAX + 1` is not representable.
We chose to interpret this fact as the indication that `INT_MIN` is out of bounds for Abs.
We deal with it the same way we deal with other domain violations:
we restrict the input interval to legal values and apply Abs to the restricted interval.

`Abs([INT_MIN; x]) = [0; INT_MAX]`

## Acos

acos is the reciprocal of the cosine function.
Expand Down Expand Up @@ -66,6 +76,8 @@ Addition is a binary operator, and the above method, designed for unary, real fu
Let us consider the addition of arguments $x$ and $y$, with respective precisions $l_x$ and $l_y$. Without loss of generality, let's assume that $l_x < l_y$, ie, $x$ is represented with more precision than $y$. In order to be able to distinguish the two sums $x + y$ and $x' + y$, where the operands $x$ and $x'$ only differ by their last bit, bits up to $l_x$ have to be conserved in the output.
Thus, we establish that $l' = min(l_x, l_y)$ is the coarsest output precision that still respects pseudo-injectivity.

### Integers

Wrapping situations due to integer overflow have to be taken care of. In the case where both operands are integers, if their sum is higher than the biggest representable integer or lower than the smallest representable integer, the default behaviour is for the value to "wrap" around and get to the other end of the integer range. This results in the output interval of the operation being `[INT_MIN; INT_MAX]`.

## And
Expand Down
2 changes: 2 additions & 0 deletions interval/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ void check(const std::string& testname, const itv::interval& exp, const itv::int
{
if (exp == res) {
std::cout << "OK: " << testname << " " << exp << " = " << res << std::endl;
if (exp.lsb() != res.lsb())
std::cout << "\t But precisions differ by " << exp.lsb() - res.lsb() << std::endl;
} else {
std::cout << "ERR:" << testname << " FAILED. We got " << exp << " instead of " << res << std::endl;
}
Expand Down
9 changes: 9 additions & 0 deletions interval/intervalAbs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ interval interval_algebra::Abs(const interval& x)
if (x.lo() >= 0) {
return x;
}

if (x.lsb() >= 0 and x.lo() <= (double)INT_MIN){
return {0, (double)INT_MAX, x.lsb()};
}
if (x.hi() <= 0) {
return {-x.hi(), -x.lo(), x.lsb()};
}

return {0, std::max(std::abs(x.lo()), std::abs(x.hi())), x.lsb()};
}

Expand All @@ -44,5 +49,9 @@ void interval_algebra::testAbs()
10, 10000, "abs", interval(-10, 10, 0), [](double x) { return std::abs(x); }, &interval_algebra::Abs);
analyzeUnaryMethod(
10, 10000, "abs", interval(-10, 10, -15), [](double x) { return std::abs(x); }, &interval_algebra::Abs);
// testing the behaviour on integers
check("abs", Abs(interval(INT_MIN, INT_MIN, 0)), interval(0, INT_MAX, 0));
check("abs", Abs(interval(INT_MIN, INT_MIN, 5)), interval(0, INT_MAX, 5));
check("abs", Abs(interval(INT_MIN, INT_MIN, -5)), interval(-(float)INT_MIN, -(float)INT_MIN, -5));
}
} // namespace itv

0 comments on commit 952c910

Please sign in to comment.