W jaki sposób można dodać dwie wartości long
w Javie, aby w razie przepełnienia wynik był zaciśnięty do zakresu Long.MIN_VALUE
.. Long.MAX_VALUE
?Nasycone dodanie dwóch podpisanych wartości Javy "długich"
Aby dodać ints można wykonywać operacje arytmetyczne w long
precyzją i oddanych wynik z powrotem do int
, np:
int saturatedAdd(int x, int y) {
long sum = (long) x + (long) y;
long clampedSum = Math.max((long) Integer.MIN_VALUE,
Math.min(sum, (long) Integer.MAX_VALUE));
return (int) clampedSum;
}
lub
import com.google.common.primitives.Ints;
int saturatedAdd(int x, int y) {
long sum = (long) x + (long) y;
return Ints.saturatedCast(sum);
}
ale w przypadku long
tam nie ma większy prymitywny typ, który może pomieścić pośrednią sumę (bez zamków).
Ponieważ jest to Java, nie mogę używać inline assembly (nasyconych instrukcji SSE jest w szczególny sposób.)
To może być realizowane za pomocą BigInteger
, np
static final BigInteger bigMin = BigInteger.valueOf(Long.MIN_VALUE);
static final BigInteger bigMax = BigInteger.valueOf(Long.MAX_VALUE);
long saturatedAdd(long x, long y) {
BigInteger sum = BigInteger.valueOf(x).add(BigInteger.valueOf(y));
return bigMin.max(sum).min(bigMax).longValue();
}
jednak wydajność jest ważne, więc ta metoda nie jest idealna (choć przydatny do testowania.)
Nie wiem, czy unikanie rozgałęzień może znacząco wpłynąć na wydajność w Javie. Zakładam, że tak, ale chciałbym porównać metody zarówno z rozgałęzieniami, jak i bez nich.
pokrewne: How to do saturating addition in C?
W rzeczywistości można użyć złożenia pod warunkiem, że zostanie on zawinięty w JNI lub JNA. Byłoby wspaniale widzieć wydajność między proponowanymi rozwiązaniami. – janislaw